[flang-commits] [flang] [llvm] [flang][OpenMP] Parse DOACROSS clause (PR #115396)

Krzysztof Parzyszek via flang-commits flang-commits at lists.llvm.org
Fri Nov 8 05:47:53 PST 2024


https://github.com/kparzysz updated https://github.com/llvm/llvm-project/pull/115396

>From c4a850e5d8c6d12160fa36594dfe5af471598de6 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Thu, 7 Nov 2024 14:24:37 -0600
Subject: [PATCH 1/2] [flang][OpenMP] Parse DOACROSS clause

Extract the SINK/SOURCE parse tree elements into a separate class
`OmpDoacross`, share them between DEPEND and DOACROSS clauses.
Most of the changes in Semantics are to accommodate the new contents
of OmpDependClause, and a mere introduction of OmpDoacrossClause.

There are no semantic checks specifically for DOACROSS.
---
 flang/include/flang/Parser/dump-parse-tree.h  |  19 +-
 flang/include/flang/Parser/parse-tree.h       |  79 +++++--
 flang/lib/Lower/OpenMP/ClauseProcessor.cpp    |  30 +--
 flang/lib/Lower/OpenMP/Clauses.cpp            | 112 +++++-----
 flang/lib/Lower/OpenMP/Clauses.h              |   2 +-
 flang/lib/Parser/openmp-parsers.cpp           |  48 +++--
 flang/lib/Parser/parse-tree.cpp               |  19 +-
 flang/lib/Parser/unparse.cpp                  |  30 +--
 flang/lib/Semantics/check-omp-structure.cpp   | 195 ++++++++++--------
 flang/lib/Semantics/check-omp-structure.h     |   1 +
 flang/lib/Semantics/resolve-directives.cpp    |   4 +-
 flang/test/Parser/OpenMP/depobj-construct.f90 |   2 +-
 flang/test/Parser/OpenMP/doacross-clause.f90  |  90 ++++++++
 flang/test/Parser/OpenMP/ordered-depend.f90   |  90 ++++++++
 .../Semantics/OpenMP/clause-validity01.f90    |   2 +-
 flang/test/Semantics/OpenMP/depend06.f90      |   4 +-
 .../Semantics/OpenMP/depobj-construct-v50.f90 |   2 +-
 .../Semantics/OpenMP/depobj-construct-v51.f90 |   4 +-
 .../Semantics/OpenMP/depobj-construct-v52.f90 |   4 +-
 flang/test/Semantics/OpenMP/ordered01.f90     |  13 +-
 flang/test/Semantics/OpenMP/ordered03.f90     |   4 +-
 llvm/include/llvm/Frontend/OpenMP/ClauseT.h   |  17 +-
 llvm/include/llvm/Frontend/OpenMP/OMP.td      |   1 +
 23 files changed, 517 insertions(+), 255 deletions(-)
 create mode 100644 flang/test/Parser/OpenMP/doacross-clause.f90
 create mode 100644 flang/test/Parser/OpenMP/ordered-depend.f90

diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h
index bfeb23de535392..f7730141ecf928 100644
--- a/flang/include/flang/Parser/dump-parse-tree.h
+++ b/flang/include/flang/Parser/dump-parse-tree.h
@@ -509,15 +509,20 @@ class ParseTreeDumper {
   NODE(parser, OmpDefaultmapClause)
   NODE_ENUM(OmpDefaultmapClause, ImplicitBehavior)
   NODE_ENUM(OmpDefaultmapClause, VariableCategory)
-  NODE(parser, OmpDependClause)
-  NODE(parser, OmpDetachClause)
-  NODE(OmpDependClause, InOut)
-  NODE(OmpDependClause, Sink)
-  NODE(OmpDependClause, Source)
+  NODE(parser, OmpDependenceType)
+  NODE_ENUM(OmpDependenceType, Type)
   NODE(parser, OmpTaskDependenceType)
   NODE_ENUM(OmpTaskDependenceType, Type)
-  NODE(parser, OmpDependSinkVec)
-  NODE(parser, OmpDependSinkVecLength)
+  NODE(parser, OmpIterationOffset)
+  NODE(parser, OmpIteration)
+  NODE(parser, OmpIterationVector)
+  NODE(parser, OmpDoacross)
+  NODE(OmpDoacross, Sink)
+  NODE(OmpDoacross, Source)
+  NODE(parser, OmpDependClause)
+  NODE(OmpDependClause, TaskDep)
+  NODE(parser, OmpDetachClause)
+  NODE(parser, OmpDoacrossClause)
   NODE(parser, OmpDestroyClause)
   NODE(parser, OmpEndAllocators)
   NODE(parser, OmpEndAtomic)
diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index d2c5b45d995813..e0369426364ede 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -3439,16 +3439,35 @@ struct OmpObject {
 
 WRAPPER_CLASS(OmpObjectList, std::list<OmpObject>);
 
+// Ref: [4.5:169-170], [5.0:255-256], [5.1:288-289]
+//
+// dependence-type ->
+//    SINK | SOURCE |           // since 4.5
+//    IN | OUT | INOUT |        // since 4.5, until 5.1
+//    MUTEXINOUTSET | DEPOBJ |  // since 5.0, until 5.1
+//    INOUTSET                  // since 5.1, until 5.1
+//
+// All of these, except SINK and SOURCE became task-dependence-type in 5.2.
+//
+// Keeping these two as separate types, since having them all together
+// creates conflicts when parsing the DEPEND clause. For DEPEND(SINK: ...),
+// the SINK may be parsed as 'task-dependence-type', and the list after
+// the ':' would then be parsed as OmpObjectList (instead of the iteration
+// vector). This would accept the vector "i, j, k" (although interpreted
+// incorrectly), while flagging a syntax error for "i+1, j, k".
+struct OmpDependenceType {
+  ENUM_CLASS(Type, Sink, Source);
+  WRAPPER_CLASS_BOILERPLATE(OmpDependenceType, Type);
+};
+
 // Ref: [4.5:169-170], [5.0:254-256], [5.1:287-289], [5.2:321]
 //
 // task-dependence-type -> // "dependence-type" in 5.1 and before
 //    IN | OUT | INOUT |        // since 4.5
-//    SOURCE | SINK |           // since 4.5, until 5.1
 //    MUTEXINOUTSET | DEPOBJ |  // since 5.0
 //    INOUTSET                  // since 5.2
 struct OmpTaskDependenceType {
-  ENUM_CLASS(
-      Type, In, Out, Inout, Inoutset, Mutexinoutset, Source, Sink, Depobj)
+  ENUM_CLASS(Type, In, Out, Inout, Inoutset, Mutexinoutset, Depobj)
   WRAPPER_CLASS_BOILERPLATE(OmpTaskDependenceType, Type);
 };
 
@@ -3528,41 +3547,55 @@ struct OmpDefaultmapClause {
   std::tuple<ImplicitBehavior, std::optional<VariableCategory>> t;
 };
 
-// 2.13.9 depend-vec-length -> +/- non-negative-constant
-struct OmpDependSinkVecLength {
-  TUPLE_CLASS_BOILERPLATE(OmpDependSinkVecLength);
+// 2.13.9 iteration-offset -> +/- non-negative-constant
+struct OmpIterationOffset {
+  TUPLE_CLASS_BOILERPLATE(OmpIterationOffset);
   std::tuple<DefinedOperator, ScalarIntConstantExpr> t;
 };
 
-// 2.13.9 depend-vec -> induction-variable [depend-vec-length], ...
-struct OmpDependSinkVec {
-  TUPLE_CLASS_BOILERPLATE(OmpDependSinkVec);
-  std::tuple<Name, std::optional<OmpDependSinkVecLength>> t;
+// 2.13.9 iteration -> induction-variable [iteration-offset]
+struct OmpIteration {
+  TUPLE_CLASS_BOILERPLATE(OmpIteration);
+  std::tuple<Name, std::optional<OmpIterationOffset>> t;
+};
+
+WRAPPER_CLASS(OmpIterationVector, std::list<OmpIteration>);
+
+// Extract this into a separate structure (instead of having it directly in
+// OmpDoacrossClause), so that the context in TYPE_CONTEXT_PARSER can be set
+// separately for OmpDependClause and OmpDoacrossClause.
+struct OmpDoacross {
+  OmpDependenceType::Type GetDepType() const;
+
+  WRAPPER_CLASS(Sink, OmpIterationVector);
+  EMPTY_CLASS(Source);
+  UNION_CLASS_BOILERPLATE(OmpDoacross);
+  std::variant<Sink, Source> u;
 };
 
 // Ref: [4.5:169-170], [5.0:255-256], [5.1:288-289], [5.2:323-324]
 //
 // depend-clause ->
 //    DEPEND(SOURCE) |                               // since 4.5, until 5.1
-//    DEPEND(SINK: depend-vec) |                     // since 4.5, until 5.1
-//    DEPEND([depend-modifier,]dependence-type: locator-list)   // since 4.5
+//    DEPEND(SINK: iteration-vector) |               // since 4.5, until 5.1
+//    DEPEND([depend-modifier,]
+//           task-dependence-type: locator-list)     // since 4.5
 //
 // 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>);
-  struct InOut {
-    TUPLE_CLASS_BOILERPLATE(InOut);
+  struct TaskDep {
+    OmpTaskDependenceType::Type GetTaskDepType() const;
+    TUPLE_CLASS_BOILERPLATE(TaskDep);
     std::tuple<std::optional<OmpIteratorModifier>, OmpTaskDependenceType,
         OmpObjectList>
         t;
   };
-  std::variant<Source, Sink, InOut> u;
+  std::variant<TaskDep, OmpDoacross> u;
 };
 
+WRAPPER_CLASS(OmpDoacrossClause, OmpDoacross);
+
 // Ref: [5.0:254-255], [5.1:287-288], [5.2:73]
 //
 // destroy-clause ->
@@ -3775,8 +3808,12 @@ struct OmpNumTasksClause {
 
 // 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);
+// update-clause -> UPDATE(dependence-type)       // since 5.0, until 5.1
+// update-clause -> UPDATE(task-dependence-type)  // since 5.2
+struct OmpUpdateClause {
+  UNION_CLASS_BOILERPLATE(OmpUpdateClause);
+  std::variant<OmpDependenceType, OmpTaskDependenceType> u;
+};
 
 // OpenMP Clauses
 struct OmpClause {
diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
index e768c1cbc0784a..72b9018f2d2808 100644
--- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
+++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
@@ -122,28 +122,28 @@ genProcBindKindAttr(fir::FirOpBuilder &firOpBuilder,
 
 static mlir::omp::ClauseTaskDependAttr
 genDependKindAttr(lower::AbstractConverter &converter,
-                  const omp::clause::Depend::TaskDependenceType kind) {
+                  const omp::clause::DependenceType kind) {
   fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
   mlir::Location currentLocation = converter.getCurrentLocation();
 
   mlir::omp::ClauseTaskDepend pbKind;
   switch (kind) {
-  case omp::clause::Depend::TaskDependenceType::In:
+  case omp::clause::DependenceType::In:
     pbKind = mlir::omp::ClauseTaskDepend::taskdependin;
     break;
-  case omp::clause::Depend::TaskDependenceType::Out:
+  case omp::clause::DependenceType::Out:
     pbKind = mlir::omp::ClauseTaskDepend::taskdependout;
     break;
-  case omp::clause::Depend::TaskDependenceType::Inout:
+  case omp::clause::DependenceType::Inout:
     pbKind = mlir::omp::ClauseTaskDepend::taskdependinout;
     break;
-  case omp::clause::Depend::TaskDependenceType::Mutexinoutset:
-  case omp::clause::Depend::TaskDependenceType::Inoutset:
+  case omp::clause::DependenceType::Mutexinoutset:
+  case omp::clause::DependenceType::Inoutset:
     TODO(currentLocation, "INOUTSET and MUTEXINOUTSET are not supported yet");
     break;
-  case omp::clause::Depend::TaskDependenceType::Depobj:
-  case omp::clause::Depend::TaskDependenceType::Sink:
-  case omp::clause::Depend::TaskDependenceType::Source:
+  case omp::clause::DependenceType::Depobj:
+  case omp::clause::DependenceType::Sink:
+  case omp::clause::DependenceType::Source:
     llvm_unreachable("unhandled parser task dependence type");
     break;
   }
@@ -803,20 +803,20 @@ bool ClauseProcessor::processDepend(mlir::omp::DependClauseOps &result) const {
   auto process = [&](const omp::clause::Depend &clause,
                      const parser::CharBlock &) {
     using Depend = omp::clause::Depend;
-    if (!std::holds_alternative<Depend::DepType>(clause.u)) {
+    if (!std::holds_alternative<Depend::TaskDep>(clause.u)) {
       TODO(converter.getCurrentLocation(),
            "DEPEND clause with SINK or SOURCE is not supported yet");
     }
-    auto &depType = std::get<Depend::DepType>(clause.u);
-    auto kind = std::get<Depend::TaskDependenceType>(depType.t);
-    auto &objects = std::get<omp::ObjectList>(depType.t);
+    auto &taskDep = std::get<Depend::TaskDep>(clause.u);
+    auto depType = std::get<clause::DependenceType>(taskDep.t);
+    auto &objects = std::get<omp::ObjectList>(taskDep.t);
 
-    if (std::get<std::optional<omp::clause::Iterator>>(depType.t)) {
+    if (std::get<std::optional<omp::clause::Iterator>>(taskDep.t)) {
       TODO(converter.getCurrentLocation(),
            "Support for iterator modifiers is not implemented yet");
     }
     mlir::omp::ClauseTaskDependAttr dependTypeOperand =
-        genDependKindAttr(converter, kind);
+        genDependKindAttr(converter, depType);
     result.dependKinds.append(objects.size(), dependTypeOperand);
 
     for (const omp::Object &object : objects) {
diff --git a/flang/lib/Lower/OpenMP/Clauses.cpp b/flang/lib/Lower/OpenMP/Clauses.cpp
index 46caafeef8e4a8..f6633dd53f6f23 100644
--- a/flang/lib/Lower/OpenMP/Clauses.cpp
+++ b/flang/lib/Lower/OpenMP/Clauses.cpp
@@ -338,27 +338,32 @@ ReductionOperator makeReductionOperator(const parser::OmpReductionOperator &inp,
       inp.u);
 }
 
-clause::TaskDependenceType
-makeDepType(const parser::OmpTaskDependenceType &inp) {
+clause::DependenceType makeDepType(const parser::OmpDependenceType &inp) {
+  switch (inp.v) {
+  case parser::OmpDependenceType::Type::Sink:
+    return clause::DependenceType::Sink;
+  case parser::OmpDependenceType::Type::Source:
+    return clause::DependenceType::Source;
+  }
+  llvm_unreachable("Unexpected dependence type");
+}
+
+clause::DependenceType makeDepType(const parser::OmpTaskDependenceType &inp) {
   switch (inp.v) {
   case parser::OmpTaskDependenceType::Type::Depobj:
-    return clause::TaskDependenceType::Depobj;
+    return clause::DependenceType::Depobj;
   case parser::OmpTaskDependenceType::Type::In:
-    return clause::TaskDependenceType::In;
+    return clause::DependenceType::In;
   case parser::OmpTaskDependenceType::Type::Inout:
-    return clause::TaskDependenceType::Inout;
+    return clause::DependenceType::Inout;
   case parser::OmpTaskDependenceType::Type::Inoutset:
-    return clause::TaskDependenceType::Inoutset;
+    return clause::DependenceType::Inoutset;
   case parser::OmpTaskDependenceType::Type::Mutexinoutset:
-    return clause::TaskDependenceType::Mutexinoutset;
+    return clause::DependenceType::Mutexinoutset;
   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;
+    return clause::DependenceType::Out;
   }
-  llvm_unreachable("Unexpected dependence type");
+  llvm_unreachable("Unexpected task dependence type");
 }
 
 // --------------------------------------------------------------------
@@ -574,49 +579,52 @@ Depend make(const parser::OmpClause::Depend &inp,
   // inp.v -> parser::OmpDependClause
   using wrapped = parser::OmpDependClause;
   using Variant = decltype(Depend::u);
-  // Iteration is the equivalent of parser::OmpDependSinkVec
+  // Iteration is the equivalent of parser::OmpIteration
   using Iteration = Doacross::Vector::value_type; // LoopIterationT
 
+  auto visitSource = [&](const parser::OmpDoacross::Source &) -> Variant {
+    return Doacross{{/*DependenceType=*/Doacross::DependenceType::Source,
+                     /*Vector=*/{}}};
+  };
+
+  auto visitSink = [&](const parser::OmpDoacross::Sink &s) -> Variant {
+    using IterOffset = parser::OmpIterationOffset;
+    auto convert2 = [&](const parser::OmpIteration &v) {
+      auto &t0 = std::get<parser::Name>(v.t);
+      auto &t1 = std::get<std::optional<IterOffset>>(v.t);
+
+      auto convert3 = [&](const IterOffset &u) {
+        auto &s0 = std::get<parser::DefinedOperator>(u.t);
+        auto &s1 = std::get<parser::ScalarIntConstantExpr>(u.t);
+        return Iteration::Distance{
+            {makeDefinedOperator(s0, semaCtx), makeExpr(s1, semaCtx)}};
+      };
+      return Iteration{{makeObject(t0, semaCtx), maybeApply(convert3, t1)}};
+    };
+    return Doacross{{/*DependenceType=*/Doacross::DependenceType::Sink,
+                     /*Vector=*/makeList(s.v.v, convert2)}};
+  };
+
+  auto visitTaskDep = [&](const wrapped::TaskDep &s) -> Variant {
+    auto &t0 = std::get<std::optional<parser::OmpIteratorModifier>>(s.t);
+    auto &t1 = std::get<parser::OmpTaskDependenceType>(s.t);
+    auto &t2 = std::get<parser::OmpObjectList>(s.t);
+
+    auto &&maybeIter =
+        maybeApply([&](auto &&s) { return makeIterator(s, semaCtx); }, t0);
+    return Depend::TaskDep{{/*DependenceType=*/makeDepType(t1),
+                            /*Iterator=*/std::move(maybeIter),
+                            /*LocatorList=*/makeObjects(t2, semaCtx)}};
+  };
+
   return Depend{Fortran::common::visit( //
       common::visitors{
           // Doacross
-          [&](const wrapped::Source &s) -> Variant {
-            return Doacross{
-                {/*DependenceType=*/Doacross::DependenceType::Source,
-                 /*Vector=*/{}}};
-          },
-          // Doacross
-          [&](const wrapped::Sink &s) -> Variant {
-            using DependLength = parser::OmpDependSinkVecLength;
-            auto convert2 = [&](const parser::OmpDependSinkVec &v) {
-              auto &t0 = std::get<parser::Name>(v.t);
-              auto &t1 = std::get<std::optional<DependLength>>(v.t);
-
-              auto convert3 = [&](const DependLength &u) {
-                auto &s0 = std::get<parser::DefinedOperator>(u.t);
-                auto &s1 = std::get<parser::ScalarIntConstantExpr>(u.t);
-                return Iteration::Distance{
-                    {makeDefinedOperator(s0, semaCtx), makeExpr(s1, semaCtx)}};
-              };
-              return Iteration{
-                  {makeObject(t0, semaCtx), maybeApply(convert3, t1)}};
-            };
-            return Doacross{{/*DependenceType=*/Doacross::DependenceType::Sink,
-                             /*Vector=*/makeList(s.v, convert2)}};
-          },
-          // Depend::DepType
-          [&](const wrapped::InOut &s) -> Variant {
-            auto &t0 =
-                std::get<std::optional<parser::OmpIteratorModifier>>(s.t);
-            auto &t1 = std::get<parser::OmpTaskDependenceType>(s.t);
-            auto &t2 = std::get<parser::OmpObjectList>(s.t);
-
-            auto &&maybeIter = maybeApply(
-                [&](auto &&s) { return makeIterator(s, semaCtx); }, t0);
-            return Depend::DepType{{/*TaskDependenceType=*/makeDepType(t1),
-                                    /*Iterator=*/std::move(maybeIter),
-                                    /*LocatorList=*/makeObjects(t2, semaCtx)}};
+          [&](const parser::OmpDoacross &s) -> Variant {
+            return common::visit(common::visitors{visitSink, visitSource}, s.u);
           },
+          // Depend::TaskDep
+          visitTaskDep,
       },
       inp.v.u)};
 }
@@ -1356,7 +1364,9 @@ Uniform make(const parser::OmpClause::Uniform &inp,
 Update make(const parser::OmpClause::Update &inp,
             semantics::SemanticsContext &semaCtx) {
   // inp.v -> parser::OmpUpdateClause
-  return Update{/*TaskDependenceType=*/makeDepType(inp.v.v)};
+  auto depType =
+      common::visit([](auto &&s) { return makeDepType(s); }, inp.v.u);
+  return Update{/*DependenceType=*/depType};
 }
 
 Use make(const parser::OmpClause::Use &inp,
diff --git a/flang/lib/Lower/OpenMP/Clauses.h b/flang/lib/Lower/OpenMP/Clauses.h
index 51180ebfe5745e..514f0d1ee466ac 100644
--- a/flang/lib/Lower/OpenMP/Clauses.h
+++ b/flang/lib/Lower/OpenMP/Clauses.h
@@ -152,7 +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;
+using DependenceType = tomp::type::DependenceType;
 
 // "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/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp
index 7a0ecc59a2c5c5..1a0f8acae4948b 100644
--- a/flang/lib/Parser/openmp-parsers.cpp
+++ b/flang/lib/Parser/openmp-parsers.cpp
@@ -392,12 +392,9 @@ TYPE_PARSER(construct<OmpAllocateClause>(
         ":"),
     Parser<OmpObjectList>{}))
 
-// 2.13.9 DEPEND (SOURCE | SINK : vec | (IN | OUT | INOUT) : list
-TYPE_PARSER(construct<OmpDependSinkVecLength>(
-    Parser<DefinedOperator>{}, scalarIntConstantExpr))
-
-TYPE_PARSER(
-    construct<OmpDependSinkVec>(name, maybe(Parser<OmpDependSinkVecLength>{})))
+TYPE_PARSER(construct<OmpDependenceType>(
+    "SINK" >> pure(OmpDependenceType::Type::Sink) ||
+    "SOURCE" >> pure(OmpDependenceType::Type::Source)))
 
 TYPE_PARSER(construct<OmpTaskDependenceType>(
     "DEPOBJ" >> pure(OmpTaskDependenceType::Type::Depobj) ||
@@ -405,18 +402,31 @@ TYPE_PARSER(construct<OmpTaskDependenceType>(
     "INOUT"_id >> pure(OmpTaskDependenceType::Type::Inout) ||
     "INOUTSET"_id >> pure(OmpTaskDependenceType::Type::Inoutset) ||
     "MUTEXINOUTSET" >> pure(OmpTaskDependenceType::Type::Mutexinoutset) ||
-    "OUT" >> pure(OmpTaskDependenceType::Type::Out) ||
-    "SINK" >> pure(OmpTaskDependenceType::Type::Sink) ||
-    "SOURCE" >> pure(OmpTaskDependenceType::Type::Source)))
+    "OUT" >> pure(OmpTaskDependenceType::Type::Out)))
+
+// iteration-offset -> +/- non-negative-constant-expr
+TYPE_PARSER(construct<OmpIterationOffset>(
+    Parser<DefinedOperator>{}, scalarIntConstantExpr))
+
+// iteration -> iteration-variable [+/- nonnegative-scalar-integer-constant]
+TYPE_PARSER(construct<OmpIteration>(name, maybe(Parser<OmpIterationOffset>{})))
+
+TYPE_PARSER(construct<OmpIterationVector>(nonemptyList(Parser<OmpIteration>{})))
+
+TYPE_PARSER(construct<OmpDoacross>(
+    construct<OmpDoacross>(construct<OmpDoacross::Sink>(
+        "SINK"_tok >> ":"_tok >> Parser<OmpIterationVector>{})) ||
+    construct<OmpDoacross>(construct<OmpDoacross::Source>("SOURCE"_tok))))
 
 TYPE_CONTEXT_PARSER("Omp Depend clause"_en_US,
-    construct<OmpDependClause>(construct<OmpDependClause::Sink>(
-        "SINK :" >> nonemptyList(Parser<OmpDependSinkVec>{}))) ||
-        construct<OmpDependClause>(
-            construct<OmpDependClause::Source>("SOURCE"_tok)) ||
-        construct<OmpDependClause>(construct<OmpDependClause::InOut>(
+    construct<OmpDependClause>(
+        construct<OmpDependClause>(construct<OmpDependClause::TaskDep>(
             maybe(Parser<OmpIteratorModifier>{} / ","_tok),
-            Parser<OmpTaskDependenceType>{} / ":", Parser<OmpObjectList>{})))
+            Parser<OmpTaskDependenceType>{} / ":", Parser<OmpObjectList>{})) ||
+        construct<OmpDependClause>(Parser<OmpDoacross>{})))
+
+TYPE_CONTEXT_PARSER("Omp Doacross clause"_en_US,
+    construct<OmpDoacrossClause>(Parser<OmpDoacross>{}))
 
 TYPE_PARSER(construct<OmpFromClause::Expectation>(
     "PRESENT" >> pure(OmpFromClause::Expectation::Present)))
@@ -466,6 +476,10 @@ TYPE_PARSER(construct<OmpDetachClause>(Parser<OmpObject>{}))
 TYPE_PARSER(construct<OmpAlignedClause>(
     Parser<OmpObjectList>{}, maybe(":" >> scalarIntConstantExpr)))
 
+TYPE_PARSER(construct<OmpUpdateClause>(
+    construct<OmpUpdateClause>(Parser<OmpDependenceType>{}) ||
+    construct<OmpUpdateClause>(Parser<OmpTaskDependenceType>{})))
+
 // 2.9.5 ORDER ([order-modifier :]concurrent)
 TYPE_PARSER(construct<OmpOrderModifier>(
     "REPRODUCIBLE" >> pure(OmpOrderModifier::Kind::Reproducible)) ||
@@ -531,6 +545,8 @@ TYPE_PARSER(
     "DIST_SCHEDULE" >>
         construct<OmpClause>(construct<OmpClause::DistSchedule>(
             parenthesized("STATIC" >> maybe("," >> scalarIntExpr)))) ||
+    "DOACROSS" >>
+        construct<OmpClause>(parenthesized(Parser<OmpDoacrossClause>{})) ||
     "DYNAMIC_ALLOCATORS" >>
         construct<OmpClause>(construct<OmpClause::DynamicAllocators>()) ||
     "ENTER" >> construct<OmpClause>(construct<OmpClause::Enter>(
@@ -634,7 +650,7 @@ TYPE_PARSER(
                      parenthesized(nonemptyList(name)))) ||
     "UNTIED" >> construct<OmpClause>(construct<OmpClause::Untied>()) ||
     "UPDATE" >> construct<OmpClause>(construct<OmpClause::Update>(
-                    parenthesized(Parser<OmpTaskDependenceType>{}))))
+                    parenthesized(Parser<OmpUpdateClause>{}))))
 
 // [Clause, [Clause], ...]
 TYPE_PARSER(sourced(construct<OmpClauseList>(
diff --git a/flang/lib/Parser/parse-tree.cpp b/flang/lib/Parser/parse-tree.cpp
index 60aef1666e9ba7..574e5fd84862e7 100644
--- a/flang/lib/Parser/parse-tree.cpp
+++ b/flang/lib/Parser/parse-tree.cpp
@@ -253,22 +253,23 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Name &x) {
   return os << x.ToString();
 }
 
-OmpTaskDependenceType::Type OmpDependClause::GetDepType() const {
-  return common::visit(
+OmpDependenceType::Type OmpDoacross::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 OmpDoacross::Sink &) {
+            return OmpDependenceType::Type::Sink;
           },
-          [&](const parser::OmpDependClause::InOut &y) {
-            return std::get<parser::OmpTaskDependenceType>(y.t).v;
+          [](const OmpDoacross::Source &) {
+            return OmpDependenceType::Type::Source;
           },
       },
       u);
 }
 
+OmpTaskDependenceType::Type OmpDependClause::TaskDep::GetTaskDepType() const {
+  return std::get<parser::OmpTaskDependenceType>(t).v;
+}
+
 } // 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 bbb126dcdb6d5e..14e128fb15bec3 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -2228,36 +2228,16 @@ class UnparseVisitor {
         std::get<std::optional<OmpNumTasksClause::Prescriptiveness>>(x.t), ":");
     Walk(std::get<ScalarIntExpr>(x.t));
   }
-  void Unparse(const OmpDependSinkVecLength &x) {
-    Walk(std::get<DefinedOperator>(x.t));
-    Walk(std::get<ScalarIntConstantExpr>(x.t));
+  void Unparse(const OmpDoacross::Sink &x) {
+    Word("SINK: ");
+    Walk(x.v.v);
   }
-  void Unparse(const OmpDependSinkVec &x) {
-    Walk(std::get<Name>(x.t));
-    Walk(std::get<std::optional<OmpDependSinkVecLength>>(x.t));
-  }
-  void Unparse(const OmpDependClause::InOut &x) {
+  void Unparse(const OmpDoacross::Source &) { Word("SOURCE"); }
+  void Unparse(const OmpDependClause::TaskDep &x) {
     Walk(std::get<OmpTaskDependenceType>(x.t));
     Put(":");
     Walk(std::get<OmpObjectList>(x.t));
   }
-  bool Pre(const OmpDependClause &x) {
-    return common::visit(
-        common::visitors{
-            [&](const OmpDependClause::Source &) {
-              Word("SOURCE");
-              return false;
-            },
-            [&](const OmpDependClause::Sink &y) {
-              Word("SINK:");
-              Walk(y.v);
-              Put(")");
-              return false;
-            },
-            [&](const OmpDependClause::InOut &) { return true; },
-        },
-        x.u);
-  }
   void Unparse(const OmpDefaultmapClause &x) {
     Walk(std::get<OmpDefaultmapClause::ImplicitBehavior>(x.t));
     Walk(":",
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 014604627f2cd1..132fb6484bcfc5 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -1623,36 +1623,37 @@ void OmpStructureChecker::ChecksOnOrderedAsStandalone() {
         "standalone construct with no ORDERED region"_err_en_US);
   }
 
-  bool isSinkPresent{false};
-  int dependSourceCount{0};
+  int dependSinkCount{0}, dependSourceCount{0};
+  bool exclusiveShown{false}, duplicateSourceShown{false};
+
+  auto visitDoacross = [&](const parser::OmpDoacross &doa,
+                           const parser::CharBlock &src) {
+    common::visit(
+        common::visitors{
+            [&](const parser::OmpDoacross::Source &) { dependSourceCount++; },
+            [&](const parser::OmpDoacross::Sink &) { dependSinkCount++; }},
+        doa.u);
+    if (!exclusiveShown && dependSinkCount > 0 && dependSourceCount > 0) {
+      exclusiveShown = true;
+      context_.Say(src,
+          "The SINK and SOURCE dependence types are mutually exclusive"_err_en_US);
+    }
+    if (!duplicateSourceShown && dependSourceCount > 1) {
+      duplicateSourceShown = true;
+      context_.Say(src,
+          "At most one SOURCE dependence type can appear on the ORDERED directive"_err_en_US);
+    }
+  };
+
   auto clauseAll = FindClauses(llvm::omp::Clause::OMPC_depend);
   for (auto itr = clauseAll.first; itr != clauseAll.second; ++itr) {
     const auto &dependClause{
         std::get<parser::OmpClause::Depend>(itr->second->u)};
-    if (std::get_if<parser::OmpDependClause::Source>(&dependClause.v.u)) {
-      dependSourceCount++;
-      if (isSinkPresent) {
-        context_.Say(itr->second->source,
-            "DEPEND(SOURCE) is not allowed when DEPEND(SINK: vec) is present "
-            "on ORDERED directive"_err_en_US);
-      }
-      if (dependSourceCount > 1) {
-        context_.Say(itr->second->source,
-            "At most one DEPEND(SOURCE) clause can appear on the ORDERED "
-            "directive"_err_en_US);
-      }
-    } else if (std::get_if<parser::OmpDependClause::Sink>(&dependClause.v.u)) {
-      isSinkPresent = true;
-      if (dependSourceCount > 0) {
-        context_.Say(itr->second->source,
-            "DEPEND(SINK: vec) is not allowed when DEPEND(SOURCE) is present "
-            "on ORDERED directive"_err_en_US);
-      }
+    if (auto *doAcross{std::get_if<parser::OmpDoacross>(&dependClause.v.u)}) {
+      visitDoacross(*doAcross, itr->second->source);
     } else {
       context_.Say(itr->second->source,
-          "Only DEPEND(SOURCE) or DEPEND(SINK: vec) are allowed when ORDERED "
-          "construct is a standalone construct with no ORDERED "
-          "region"_err_en_US);
+          "Only SINK or SOURCE dependence types are allowed when ORDERED construct is a standalone construct with no ORDERED region"_err_en_US);
     }
   }
 
@@ -1681,20 +1682,23 @@ void OmpStructureChecker::ChecksOnOrderedAsStandalone() {
 }
 
 void OmpStructureChecker::CheckOrderedDependClause(
-    std::optional<std::int64_t> orderedValue) {
-  auto clauseAll{FindClauses(llvm::omp::Clause::OMPC_depend)};
-  for (auto itr = clauseAll.first; itr != clauseAll.second; ++itr) {
-    const auto &dependClause{
-        std::get<parser::OmpClause::Depend>(itr->second->u)};
-    if (const auto *sinkVectors{
-            std::get_if<parser::OmpDependClause::Sink>(&dependClause.v.u)}) {
-      std::int64_t numVar = sinkVectors->v.size();
+    std::optional<int64_t> orderedValue) {
+  auto visitDoacross = [&](const parser::OmpDoacross &doa,
+                           const parser::CharBlock &src) {
+    if (auto *sinkVector{std::get_if<parser::OmpDoacross::Sink>(&doa.u)}) {
+      int64_t numVar = sinkVector->v.v.size();
       if (orderedValue != numVar) {
-        context_.Say(itr->second->source,
-            "The number of variables in DEPEND(SINK: vec) clause does not "
-            "match the parameter specified in ORDERED clause"_err_en_US);
+        context_.Say(src,
+            "The number of variables in the SINK iteration vector does not match the parameter specified in ORDERED clause"_err_en_US);
       }
     }
+  };
+  auto clauseAll{FindClauses(llvm::omp::Clause::OMPC_depend)};
+  for (auto itr = clauseAll.first; itr != clauseAll.second; ++itr) {
+    auto &dependClause{std::get<parser::OmpClause::Depend>(itr->second->u)};
+    if (auto *doAcross{std::get_if<parser::OmpDoacross>(&dependClause.v.u)}) {
+      visitDoacross(*doAcross, itr->second->source);
+    }
   }
 }
 
@@ -1736,17 +1740,13 @@ void OmpStructureChecker::CheckTaskDependenceType(
     const parser::OmpTaskDependenceType::Type &x) {
   // Common checks for task-dependence-type (DEPEND and UPDATE clauses).
   unsigned version{context_.langOptions().OpenMPVersion};
-  unsigned since{0}, deprecatedIn{~0u};
+  unsigned since{0};
 
   switch (x) {
   case parser::OmpTaskDependenceType::Type::In:
   case parser::OmpTaskDependenceType::Type::Out:
   case parser::OmpTaskDependenceType::Type::Inout:
     break;
-  case parser::OmpTaskDependenceType::Type::Source:
-  case parser::OmpTaskDependenceType::Type::Sink:
-    deprecatedIn = 52;
-    break;
   case parser::OmpTaskDependenceType::Type::Mutexinoutset:
   case parser::OmpTaskDependenceType::Type::Depobj:
     since = 50;
@@ -1756,21 +1756,36 @@ void OmpStructureChecker::CheckTaskDependenceType(
     break;
   }
 
-  if (version >= deprecatedIn) {
+  if (version < since) {
     context_.Say(GetContext().clauseSource,
-        "%s task-dependence-type is deprecated in %s"_warn_en_US,
-        parser::ToUpperCaseLetters(
-            parser::OmpTaskDependenceType::EnumToString(x)),
-        ThisVersion(deprecatedIn));
-  } else if (version < since) {
-    context_.Say(GetContext().clauseSource,
-        "%s task-dependence-type is not supported in %s, %s"_warn_en_US,
+        "%s task dependence type is not supported in %s, %s"_warn_en_US,
         parser::ToUpperCaseLetters(
             parser::OmpTaskDependenceType::EnumToString(x)),
         ThisVersion(version), TryVersion(since));
   }
 }
 
+void OmpStructureChecker::CheckDependenceType(
+    const parser::OmpDependenceType::Type &x) {
+  // Common checks for dependence-type (DEPEND and UPDATE clauses).
+  unsigned version{context_.langOptions().OpenMPVersion};
+  unsigned deprecatedIn{~0u};
+
+  switch (x) {
+  case parser::OmpDependenceType::Type::Source:
+  case parser::OmpDependenceType::Type::Sink:
+    deprecatedIn = 52;
+    break;
+  }
+
+  if (version >= deprecatedIn) {
+    context_.Say(GetContext().clauseSource,
+        "%s dependence type is deprecated in %s"_warn_en_US,
+        parser::ToUpperCaseLetters(parser::OmpDependenceType::EnumToString(x)),
+        ThisVersion(deprecatedIn));
+  }
+}
+
 void OmpStructureChecker::Enter(
     const parser::OpenMPSimpleStandaloneConstruct &x) {
   const auto &dir{std::get<parser::OmpSimpleStandaloneDirective>(x.t)};
@@ -3434,41 +3449,50 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Device &x) {
 
 void OmpStructureChecker::Enter(const parser::OmpClause::Depend &x) {
   CheckAllowedClause(llvm::omp::Clause::OMPC_depend);
-  llvm::omp::Directive directive{GetContext().directive};
+  llvm::omp::Directive dir{GetContext().directive};
   unsigned version{context_.langOptions().OpenMPVersion};
 
-  using DepType = parser::OmpTaskDependenceType::Type;
-  DepType depType = x.v.GetDepType();
+  auto *doaDep{std::get_if<parser::OmpDoacross>(&x.v.u)};
+  auto *taskDep{std::get_if<parser::OmpDependClause::TaskDep>(&x.v.u)};
+  assert(((doaDep == nullptr) != (taskDep == nullptr)) &&
+      "Unexpected alternative in update clause");
 
-  CheckTaskDependenceType(depType);
+  if (doaDep) {
+    CheckDependenceType(doaDep->GetDepType());
+  } else {
+    CheckTaskDependenceType(taskDep->GetTaskDepType());
+  }
 
-  if (directive == llvm::omp::OMPD_depobj) {
+  if (dir == 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;
+      bool invalidDep{false};
+      if (taskDep) {
+        if (version == 50) {
+          invalidDep = taskDep->GetTaskDepType() ==
+              parser::OmpTaskDependenceType::Type::Depobj;
+        }
+      } else {
+        invalidDep = true;
       }
       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");
+            "A DEPEND clause on a DEPOBJ construct must not have %s as dependence type"_err_en_US,
+            version == 50 ? "SINK, SOURCE or DEPOBJ" : "SINK or SOURCE");
       }
     }
-  } else if (directive != llvm::omp::OMPD_ordered) {
-    if (depType == DepType::Source || depType == DepType::Sink) {
+  } else if (dir != llvm::omp::OMPD_ordered) {
+    if (doaDep) {
       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)));
+          "The SINK and SOURCE dependence types can only be used with the ORDERED directive, used here in the %s construct"_err_en_US,
+          parser::ToUpperCaseLetters(getDirectiveName(dir)));
     }
   }
-  if (const auto *inOut{std::get_if<parser::OmpDependClause::InOut>(&x.v.u)}) {
-    auto &objList{std::get<parser::OmpObjectList>(inOut->t)};
-    if (directive == llvm::omp::OMPD_depobj) {
+  if (taskDep) {
+    auto &objList{std::get<parser::OmpObjectList>(taskDep->t)};
+    if (dir == 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) {
@@ -3495,14 +3519,14 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Depend &x) {
         }
       }
     }
-    if (std::get<std::optional<parser::OmpIteratorModifier>>(inOut->t)) {
+    if (std::get<std::optional<parser::OmpIteratorModifier>>(taskDep->t)) {
       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) {
+        if (dir == 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 "
@@ -3624,29 +3648,36 @@ void OmpStructureChecker::CheckStructureElement(
 
 void OmpStructureChecker::Enter(const parser::OmpClause::Update &x) {
   CheckAllowedClause(llvm::omp::Clause::OMPC_update);
-  llvm::omp::Directive directive{GetContext().directive};
+  llvm::omp::Directive dir{GetContext().directive};
   unsigned version{context_.langOptions().OpenMPVersion};
 
-  CheckTaskDependenceType(x.v.v.v);
+  auto *depType{std::get_if<parser::OmpDependenceType>(&x.v.u)};
+  auto *taskType{std::get_if<parser::OmpTaskDependenceType>(&x.v.u)};
+  assert(((depType == nullptr) != (taskType == nullptr)) &&
+      "Unexpected alternative in update clause");
+
+  if (depType) {
+    CheckDependenceType(depType->v);
+  } else if (taskType) {
+    CheckTaskDependenceType(taskType->v);
+  }
 
   // [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 (dir == 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:
+      bool invalidDep{false};
+      if (taskType) {
+        invalidDep = taskType->v == parser::OmpTaskDependenceType::Type::Depobj;
+      } else {
+        invalidDep = true;
+      }
+      if (invalidDep) {
         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;
+            "An UPDATE clause on a DEPOBJ construct must not have SINK, SOURCE or DEPOBJ as dependence type"_err_en_US);
       }
     }
   }
diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index d9236be8bced4f..9efacaa9710084 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -202,6 +202,7 @@ class OmpStructureChecker
   void CheckSIMDNest(const parser::OpenMPConstruct &x);
   void CheckTargetNest(const parser::OpenMPConstruct &x);
   void CheckTargetUpdate();
+  void CheckDependenceType(const parser::OmpDependenceType::Type &x);
   void CheckTaskDependenceType(const parser::OmpTaskDependenceType::Type &x);
   void CheckCancellationNest(
       const parser::CharBlock &source, const parser::OmpCancelType::Type &type);
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index c2b5b9673239b9..632d7e918ac64f 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -553,7 +553,7 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
     return false;
   }
 
-  void Post(const parser::OmpDependSinkVec &x) {
+  void Post(const parser::OmpIteration &x) {
     const auto &name{std::get<parser::Name>(x.t)};
     ResolveName(&name);
   }
@@ -1138,7 +1138,7 @@ bool AccAttributeVisitor::Pre(const parser::OpenACCCombinedConstruct &x) {
 static bool IsLastNameArray(const parser::Designator &designator) {
   const auto &name{GetLastName(designator)};
   const evaluate::DataRef dataRef{*(name.symbol)};
-  return common::visit(
+  return common::visit( //
       common::visitors{
           [](const evaluate::SymbolRef &ref) {
             return ref->Rank() > 0 ||
diff --git a/flang/test/Parser/OpenMP/depobj-construct.f90 b/flang/test/Parser/OpenMP/depobj-construct.f90
index 7c474071bc1e67..3de190c95bb734 100644
--- a/flang/test/Parser/OpenMP/depobj-construct.f90
+++ b/flang/test/Parser/OpenMP/depobj-construct.f90
@@ -14,7 +14,7 @@ subroutine f00
 !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: | OmpClause -> Depend -> OmpDependClause -> TaskDep
 !PARSE-TREE: | | OmpTaskDependenceType -> Type = In
 !PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'y'
 
diff --git a/flang/test/Parser/OpenMP/doacross-clause.f90 b/flang/test/Parser/OpenMP/doacross-clause.f90
new file mode 100644
index 00000000000000..afd27d9d727e04
--- /dev/null
+++ b/flang/test/Parser/OpenMP/doacross-clause.f90
@@ -0,0 +1,90 @@
+!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(x)
+  integer :: x(10, 10)
+  !$omp do ordered(2)
+  do i = 1, 10
+    do j = 1, 10
+      !$omp ordered doacross(source)
+      x(i, j) = i + j
+    enddo
+  enddo
+  !$omp end do
+end
+
+!UNPARSE: SUBROUTINE f00 (x)
+!UNPARSE:  INTEGER x(10_4,10_4)
+!UNPARSE: !$OMP DO  ORDERED(2_4)
+!UNPARSE:  DO i=1_4,10_4
+!UNPARSE:   DO j=1_4,10_4
+!UNPARSE: !$OMP ORDERED  DOACROSS(SOURCE)
+!UNPARSE:     x(int(i,kind=8),int(j,kind=8))=i+j
+!UNPARSE:   END DO
+!UNPARSE:  END DO
+!UNPARSE: !$OMP END DO
+!UNPARSE: END SUBROUTINE
+
+!PARSE-TREE-LABEL: ProgramUnit -> SubroutineSubprogram
+!PARSE-TREE: OmpBeginLoopDirective
+!PARSE-TREE: | OmpLoopDirective -> llvm::omp::Directive = do
+!PARSE-TREE: | OmpClauseList -> OmpClause -> Ordered -> Scalar -> Integer -> Constant -> Expr = '2_4'
+!PARSE-TREE: | | LiteralConstant -> IntLiteralConstant = '2'
+![...]
+!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPStandaloneConstruct -> OpenMPSimpleStandaloneConstruct
+!PARSE-TREE: | OmpSimpleStandaloneDirective -> llvm::omp::Directive = ordered
+!PARSE-TREE: | OmpClauseList -> OmpClause -> Doacross -> OmpDoacrossClause -> OmpDoacross -> Source
+
+subroutine f01(x)
+  integer :: x(10, 10)
+  !$omp do ordered(2)
+  do i = 1, 10
+    do j = 1, 10
+      !$omp ordered doacross(sink: i+1, j-2), doacross(sink: i, j+3)
+      x(i, j) = i + j
+    enddo
+  enddo
+  !$omp end do
+end
+
+!UNPARSE: SUBROUTINE f01 (x)
+!UNPARSE:  INTEGER x(10_4,10_4)
+!UNPARSE: !$OMP DO  ORDERED(2_4)
+!UNPARSE:  DO i=1_4,10_4
+!UNPARSE:   DO j=1_4,10_4
+!UNPARSE: !$OMP ORDERED  DOACROSS(SINK: i+1_4, j-2_4) DOACROSS(SINK: i, j+3_4)
+!UNPARSE:     x(int(i,kind=8),int(j,kind=8))=i+j
+!UNPARSE:   END DO
+!UNPARSE:  END DO
+!UNPARSE: !$OMP END DO
+!UNPARSE: END SUBROUTINE
+
+!PARSE-TREE-LABEL: ProgramUnit -> SubroutineSubprogram
+!PARSE-TREE: OmpBeginLoopDirective
+!PARSE-TREE: | OmpLoopDirective -> llvm::omp::Directive = do
+!PARSE-TREE: | OmpClauseList -> OmpClause -> Ordered -> Scalar -> Integer -> Constant -> Expr = '2_4'
+!PARSE-TREE: | | LiteralConstant -> IntLiteralConstant = '2'
+![...]
+!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPStandaloneConstruct -> OpenMPSimpleStandaloneConstruct
+!PARSE-TREE: | OmpSimpleStandaloneDirective -> llvm::omp::Directive = ordered
+!PARSE-TREE: | OmpClauseList -> OmpClause -> Doacross -> OmpDoacrossClause -> OmpDoacross -> Sink -> OmpIterationVector -> OmpIteration
+!PARSE-TREE: | | Name = 'i'
+!PARSE-TREE: | | OmpIterationOffset
+!PARSE-TREE: | | | DefinedOperator -> IntrinsicOperator = Add
+!PARSE-TREE: | | | Scalar -> Integer -> Constant -> Expr = '1_4'
+!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '1'
+!PARSE-TREE: | OmpIteration
+!PARSE-TREE: | | Name = 'j'
+!PARSE-TREE: | | OmpIterationOffset
+!PARSE-TREE: | | | DefinedOperator -> IntrinsicOperator = Subtract
+!PARSE-TREE: | | | Scalar -> Integer -> Constant -> Expr = '2_4'
+!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '2'
+!PARSE-TREE: | OmpClause -> Doacross -> OmpDoacrossClause -> OmpDoacross -> Sink -> OmpIterationVector -> OmpIteration
+!PARSE-TREE: | | Name = 'i'
+!PARSE-TREE: | OmpIteration
+!PARSE-TREE: | | Name = 'j'
+!PARSE-TREE: | | OmpIterationOffset
+!PARSE-TREE: | | | DefinedOperator -> IntrinsicOperator = Add
+!PARSE-TREE: | | | Scalar -> Integer -> Constant -> Expr = '3_4'
+!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '3'
+
diff --git a/flang/test/Parser/OpenMP/ordered-depend.f90 b/flang/test/Parser/OpenMP/ordered-depend.f90
new file mode 100644
index 00000000000000..9e0946af0f09ae
--- /dev/null
+++ b/flang/test/Parser/OpenMP/ordered-depend.f90
@@ -0,0 +1,90 @@
+!RUN: %flang_fc1 -fdebug-unparse -fopenmp -fopenmp-version=45 %s | FileCheck --ignore-case --check-prefix="UNPARSE" %s
+!RUN: %flang_fc1 -fdebug-dump-parse-tree -fopenmp -fopenmp-version=45 %s | FileCheck --check-prefix="PARSE-TREE" %s
+
+subroutine f00(x)
+  integer :: x(10, 10)
+  !$omp do ordered(2)
+  do i = 1, 10
+    do j = 1, 10
+      !$omp ordered depend(source)
+      x(i, j) = i + j
+    enddo
+  enddo
+  !$omp end do
+end
+
+!UNPARSE: SUBROUTINE f00 (x)
+!UNPARSE:  INTEGER x(10_4,10_4)
+!UNPARSE: !$OMP DO  ORDERED(2_4)
+!UNPARSE:  DO i=1_4,10_4
+!UNPARSE:   DO j=1_4,10_4
+!UNPARSE: !$OMP ORDERED  DEPEND(SOURCE)
+!UNPARSE:     x(int(i,kind=8),int(j,kind=8))=i+j
+!UNPARSE:   END DO
+!UNPARSE:  END DO
+!UNPARSE: !$OMP END DO
+!UNPARSE: END SUBROUTINE
+
+!PARSE-TREE-LABEL: ProgramUnit -> SubroutineSubprogram
+!PARSE-TREE: OmpBeginLoopDirective
+!PARSE-TREE: | OmpLoopDirective -> llvm::omp::Directive = do
+!PARSE-TREE: | OmpClauseList -> OmpClause -> Ordered -> Scalar -> Integer -> Constant -> Expr = '2_4'
+!PARSE-TREE: | | LiteralConstant -> IntLiteralConstant = '2'
+![...]
+!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPStandaloneConstruct -> OpenMPSimpleStandaloneConstruct
+!PARSE-TREE: | OmpSimpleStandaloneDirective -> llvm::omp::Directive = ordered
+!PARSE-TREE: | OmpClauseList -> OmpClause -> Depend -> OmpDependClause -> OmpDoacross -> Source
+
+subroutine f01(x)
+  integer :: x(10, 10)
+  !$omp do ordered(2)
+  do i = 1, 10
+    do j = 1, 10
+      !$omp ordered depend(sink: i+1, j-2), depend(sink: i, j+3)
+      x(i, j) = i + j
+    enddo
+  enddo
+  !$omp end do
+end
+
+!UNPARSE: SUBROUTINE f01 (x)
+!UNPARSE:  INTEGER x(10_4,10_4)
+!UNPARSE: !$OMP DO  ORDERED(2_4)
+!UNPARSE:  DO i=1_4,10_4
+!UNPARSE:   DO j=1_4,10_4
+!UNPARSE: !$OMP ORDERED  DEPEND(SINK: i+1_4, j-2_4) DEPEND(SINK: i, j+3_4)
+!UNPARSE:     x(int(i,kind=8),int(j,kind=8))=i+j
+!UNPARSE:   END DO
+!UNPARSE:  END DO
+!UNPARSE: !$OMP END DO
+!UNPARSE: END SUBROUTINE
+
+!PARSE-TREE-LABEL: ProgramUnit -> SubroutineSubprogram
+!PARSE-TREE: OmpBeginLoopDirective
+!PARSE-TREE: | OmpLoopDirective -> llvm::omp::Directive = do
+!PARSE-TREE: | OmpClauseList -> OmpClause -> Ordered -> Scalar -> Integer -> Constant -> Expr = '2_4'
+!PARSE-TREE: | | LiteralConstant -> IntLiteralConstant = '2'
+![...]
+!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPStandaloneConstruct -> OpenMPSimpleStandaloneConstruct
+!PARSE-TREE: | OmpSimpleStandaloneDirective -> llvm::omp::Directive = ordered
+!PARSE-TREE: | OmpClauseList -> OmpClause -> Depend -> OmpDependClause -> OmpDoacross -> Sink -> OmpIterationVector -> OmpIteration
+!PARSE-TREE: | | Name = 'i'
+!PARSE-TREE: | | OmpIterationOffset
+!PARSE-TREE: | | | DefinedOperator -> IntrinsicOperator = Add
+!PARSE-TREE: | | | Scalar -> Integer -> Constant -> Expr = '1_4'
+!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '1'
+!PARSE-TREE: | OmpIteration
+!PARSE-TREE: | | Name = 'j'
+!PARSE-TREE: | | OmpIterationOffset
+!PARSE-TREE: | | | DefinedOperator -> IntrinsicOperator = Subtract
+!PARSE-TREE: | | | Scalar -> Integer -> Constant -> Expr = '2_4'
+!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '2'
+!PARSE-TREE: | OmpClause -> Depend -> OmpDependClause -> OmpDoacross -> Sink -> OmpIterationVector -> OmpIteration
+!PARSE-TREE: | | Name = 'i'
+!PARSE-TREE: | OmpIteration
+!PARSE-TREE: | | Name = 'j'
+!PARSE-TREE: | | OmpIterationOffset
+!PARSE-TREE: | | | DefinedOperator -> IntrinsicOperator = Add
+!PARSE-TREE: | | | Scalar -> Integer -> Constant -> Expr = '3_4'
+!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '3'
+
diff --git a/flang/test/Semantics/OpenMP/clause-validity01.f90 b/flang/test/Semantics/OpenMP/clause-validity01.f90
index 124f1a02d99fba..406d30b38948ea 100644
--- a/flang/test/Semantics/OpenMP/clause-validity01.f90
+++ b/flang/test/Semantics/OpenMP/clause-validity01.f90
@@ -495,7 +495,7 @@
   !$omp taskyield
   !$omp barrier
   !$omp taskwait
-  !ERROR: DEPEND(SOURCE) or DEPEND(SINK : vec) can be used only with the ordered directive. Used here in the TASKWAIT construct.
+  !ERROR: The SINK and SOURCE dependence types can only be used with the ORDERED directive, used here in the TASKWAIT construct
   !$omp taskwait depend(source)
   ! !$omp taskwait depend(sink:i-1)
   ! !$omp target enter data map(to:arrayA) map(alloc:arrayB)
diff --git a/flang/test/Semantics/OpenMP/depend06.f90 b/flang/test/Semantics/OpenMP/depend06.f90
index a9668c552f967c..d2e6a114676c3a 100644
--- a/flang/test/Semantics/OpenMP/depend06.f90
+++ b/flang/test/Semantics/OpenMP/depend06.f90
@@ -2,7 +2,7 @@
 
 subroutine f00(x)
   integer :: x
-!WARNING: INOUTSET task-dependence-type is not supported in OpenMP v4.5, try -fopenmp-version=52
+!WARNING: INOUTSET task dependence type is not supported in OpenMP v4.5, try -fopenmp-version=52
   !$omp task depend(inoutset: x)
   x = x + 1
   !$omp end task
@@ -10,7 +10,7 @@ subroutine f00(x)
 
 subroutine f01(x)
   integer :: x
-!WARNING: MUTEXINOUTSET task-dependence-type is not supported in OpenMP v4.5, try -fopenmp-version=50
+!WARNING: MUTEXINOUTSET task dependence type is not supported in OpenMP v4.5, try -fopenmp-version=50
   !$omp task depend(mutexinoutset: x)
   x = x + 1
   !$omp end task
diff --git a/flang/test/Semantics/OpenMP/depobj-construct-v50.f90 b/flang/test/Semantics/OpenMP/depobj-construct-v50.f90
index e87d86ca54bee7..76661785826b4e 100644
--- a/flang/test/Semantics/OpenMP/depobj-construct-v50.f90
+++ b/flang/test/Semantics/OpenMP/depobj-construct-v50.f90
@@ -2,7 +2,7 @@
 
 subroutine f00
   integer :: obj
-!ERROR: A DEPEND clause on a DEPOBJ construct must not have SOURCE, SINK or DEPOBJ as dependence-type
+!ERROR: A DEPEND clause on a DEPOBJ construct must not have SINK, SOURCE or DEPOBJ as dependence type
   !$omp depobj(obj) depend(source)
 end
 
diff --git a/flang/test/Semantics/OpenMP/depobj-construct-v51.f90 b/flang/test/Semantics/OpenMP/depobj-construct-v51.f90
index fa0c025a110100..fc403f0b2db220 100644
--- a/flang/test/Semantics/OpenMP/depobj-construct-v51.f90
+++ b/flang/test/Semantics/OpenMP/depobj-construct-v51.f90
@@ -2,12 +2,12 @@
 
 subroutine f04
   integer :: obj
-!ERROR: An UPDATE clause on a DEPOBJ construct must not have SOURCE, SINK or DEPOBJ as dependence-type
+!ERROR: An UPDATE clause on a DEPOBJ construct must not have SINK, SOURCE 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
+!ERROR: An UPDATE clause on a DEPOBJ construct must not have SINK, SOURCE 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
index 42a2102500ea75..644090d7f7e8b8 100644
--- a/flang/test/Semantics/OpenMP/depobj-construct-v52.f90
+++ b/flang/test/Semantics/OpenMP/depobj-construct-v52.f90
@@ -2,8 +2,8 @@
 
 subroutine f00
   integer :: obj
-!WARNING: 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
+!WARNING: SOURCE dependence type is deprecated in OpenMP v5.2
+!ERROR: A DEPEND clause on a DEPOBJ construct must not have SINK or SOURCE as dependence type
   !$omp depobj(obj) depend(source)
 end
 
diff --git a/flang/test/Semantics/OpenMP/ordered01.f90 b/flang/test/Semantics/OpenMP/ordered01.f90
index 9433120fab10f6..9f3a258d470a6f 100644
--- a/flang/test/Semantics/OpenMP/ordered01.f90
+++ b/flang/test/Semantics/OpenMP/ordered01.f90
@@ -37,17 +37,16 @@ program main
 
   !$omp do ordered(1)
   do i = 2, N
-    !ERROR: Only DEPEND(SOURCE) or DEPEND(SINK: vec) are allowed when ORDERED construct is a standalone construct with no ORDERED region
-    !ERROR: At most one DEPEND(SOURCE) clause can appear on the ORDERED directive
+    !ERROR: Only SINK or SOURCE dependence types are allowed when ORDERED construct is a standalone construct with no ORDERED region
+    !ERROR: At most one SOURCE dependence type can appear on the ORDERED directive
     !$omp ordered depend(source) depend(inout: arrayA) depend(source)
     arrayA(i) = foo(i)
-    !ERROR: DEPEND(SOURCE) is not allowed when DEPEND(SINK: vec) is present on ORDERED directive
-    !ERROR: DEPEND(SOURCE) is not allowed when DEPEND(SINK: vec) is present on ORDERED directive
-    !ERROR: At most one DEPEND(SOURCE) clause can appear on the ORDERED directive
+    !ERROR: The SINK and SOURCE dependence types are mutually exclusive
+    !ERROR: At most one SOURCE dependence type can appear on the ORDERED directive
     !$omp ordered depend(sink: i - 1) depend(source) depend(source)
     arrayB(i) = bar(arrayA(i), arrayB(i-1))
-    !ERROR: Only DEPEND(SOURCE) or DEPEND(SINK: vec) are allowed when ORDERED construct is a standalone construct with no ORDERED region
-    !ERROR: Only DEPEND(SOURCE) or DEPEND(SINK: vec) are allowed when ORDERED construct is a standalone construct with no ORDERED region
+    !ERROR: Only SINK or SOURCE dependence types are allowed when ORDERED construct is a standalone construct with no ORDERED region
+    !ERROR: Only SINK or SOURCE dependence types are allowed when ORDERED construct is a standalone construct with no ORDERED region
     !$omp ordered depend(out: arrayC) depend(in: arrayB)
     arrayC(i) = baz(arrayB(i-1))
   end do
diff --git a/flang/test/Semantics/OpenMP/ordered03.f90 b/flang/test/Semantics/OpenMP/ordered03.f90
index 18f85fc24a9fb4..e96d4557f8f18b 100644
--- a/flang/test/Semantics/OpenMP/ordered03.f90
+++ b/flang/test/Semantics/OpenMP/ordered03.f90
@@ -99,7 +99,7 @@ subroutine sub1()
 
   !$omp do ordered(1)
   do i = 1, N
-    !ERROR: The number of variables in DEPEND(SINK: vec) clause does not match the parameter specified in ORDERED clause
+    !ERROR: The number of variables in the SINK iteration vector does not match the parameter specified in ORDERED clause
     !$omp ordered depend(sink: i - 1) depend(sink: i - 1, j)
     arrayB(i) = bar(i - 1, j)
   end do
@@ -108,7 +108,7 @@ subroutine sub1()
   !$omp do ordered(2)
   do i = 1, N
     do j = 1, N
-      !ERROR: The number of variables in DEPEND(SINK: vec) clause does not match the parameter specified in ORDERED clause
+      !ERROR: The number of variables in the SINK iteration vector does not match the parameter specified in ORDERED clause
       !$omp ordered depend(sink: i - 1) depend(sink: i - 1, j)
       arrayB(i) = foo(i - 1) + bar(i - 1, j)
     end do
diff --git a/llvm/include/llvm/Frontend/OpenMP/ClauseT.h b/llvm/include/llvm/Frontend/OpenMP/ClauseT.h
index 8ff15b51f1abdf..f4e089db0080ea 100644
--- a/llvm/include/llvm/Frontend/OpenMP/ClauseT.h
+++ b/llvm/include/llvm/Frontend/OpenMP/ClauseT.h
@@ -238,8 +238,9 @@ struct MapperT {
 // When used as arguments for other clauses, e.g. `fail`.
 ENUM(MemoryOrder, AcqRel, Acquire, Relaxed, Release, SeqCst);
 ENUM(MotionExpectation, Present);
+// Union of `dependence-type` and `task-depenence-type`.
 // V5.2: [15.9.1] `task-dependence-type` modifier
-ENUM(TaskDependenceType, Depobj, In, Inout, Inoutset, Mutexinoutset, Out, Sink,
+ENUM(DependenceType, Depobj, In, Inout, Inoutset, Mutexinoutset, Out, Sink,
      Source);
 
 template <typename I, typename E> //
@@ -502,17 +503,17 @@ template <typename T, typename I, typename E> //
 struct DependT {
   using Iterator = type::IteratorT<T, I, E>;
   using LocatorList = ObjectListT<I, E>;
-  using TaskDependenceType = tomp::type::TaskDependenceType;
+  using DependenceType = tomp::type::DependenceType;
 
-  struct DepType { // The form with task dependence type.
+  struct TaskDep { // The form with task dependence type.
     using TupleTrait = std::true_type;
     // Empty LocatorList means "omp_all_memory".
-    std::tuple<TaskDependenceType, OPT(Iterator), LocatorList> t;
+    std::tuple<DependenceType, OPT(Iterator), LocatorList> t;
   };
 
   using Doacross = DoacrossT<T, I, E>;
   using UnionTrait = std::true_type;
-  std::variant<Doacross, DepType> u; // Doacross form is legacy
+  std::variant<Doacross, TaskDep> u; // Doacross form is legacy
 };
 
 // V5.2: [3.5] `destroy` clause
@@ -562,7 +563,7 @@ struct DistScheduleT {
 template <typename T, typename I, typename E> //
 struct DoacrossT {
   using Vector = ListT<type::LoopIterationT<I, E>>;
-  ENUM(DependenceType, Source, Sink);
+  using DependenceType = tomp::type::DependenceType;
   using TupleTrait = std::true_type;
   // Empty Vector means "omp_cur_iteration"
   std::tuple<DependenceType, Vector> t;
@@ -1162,9 +1163,9 @@ struct UntiedT {
 // V5.2: [15.9.3] `update` clause
 template <typename T, typename I, typename E> //
 struct UpdateT {
-  using TaskDependenceType = tomp::type::TaskDependenceType;
+  using DependenceType = tomp::type::DependenceType;
   using WrapperTrait = std::true_type;
-  OPT(TaskDependenceType) v;
+  OPT(DependenceType) v;
 };
 
 // V5.2: [14.1.3] `use` clause
diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td
index 36834939d9b451..e81cdb681cb99d 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMP.td
+++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td
@@ -151,6 +151,7 @@ def OMPC_DistSchedule : Clause<"dist_schedule"> {
 }
 def OMPC_Doacross : Clause<"doacross"> {
   let clangClass = "OMPDoacrossClause";
+  let flangClass = "OmpDoacrossClause";
 }
 def OMPC_DynamicAllocators : Clause<"dynamic_allocators"> {
   let clangClass = "OMPDynamicAllocatorsClause";

>From b1fd415dbb1494a68ed729a3070bcd8e60902774 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Fri, 8 Nov 2024 07:47:18 -0600
Subject: [PATCH 2/2] fix example

---
 flang/examples/FeatureList/FeatureList.cpp | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/flang/examples/FeatureList/FeatureList.cpp b/flang/examples/FeatureList/FeatureList.cpp
index 62f8d39a8abaa5..dc68f160f5d924 100644
--- a/flang/examples/FeatureList/FeatureList.cpp
+++ b/flang/examples/FeatureList/FeatureList.cpp
@@ -470,13 +470,17 @@ struct NodeVisitor {
   READ_FEATURE(OmpDefaultmapClause::ImplicitBehavior)
   READ_FEATURE(OmpDefaultmapClause::VariableCategory)
   READ_FEATURE(OmpDependClause)
-  READ_FEATURE(OmpDependClause::InOut)
-  READ_FEATURE(OmpDependClause::Sink)
-  READ_FEATURE(OmpDependClause::Source)
+  READ_FEATURE(OmpDependClause::TaskDep)
+  READ_FEATURE(OmpDoacross::Sink)
+  READ_FEATURE(OmpDoacross::Source)
+  READ_FEATURE(OmpDoacrossClause)
+  READ_FEATURE(OmpDependenceType)
+  READ_FEATURE(OmpDependenceType::Type)
   READ_FEATURE(OmpTaskDependenceType)
   READ_FEATURE(OmpTaskDependenceType::Type)
-  READ_FEATURE(OmpDependSinkVec)
-  READ_FEATURE(OmpDependSinkVecLength)
+  READ_FEATURE(OmpIteration)
+  READ_FEATURE(OmpIterationOffset)
+  READ_FEATURE(OmpIterationVector)
   READ_FEATURE(OmpEndAllocators)
   READ_FEATURE(OmpEndAtomic)
   READ_FEATURE(OmpEndBlockDirective)



More information about the flang-commits mailing list