[flang-commits] [flang] 1c6ec29 - [flang][OpenMP] Parsing support for iterator modifiers in FROM and TO (#114593)

via flang-commits flang-commits at lists.llvm.org
Mon Nov 4 08:45:01 PST 2024


Author: Krzysztof Parzyszek
Date: 2024-11-04T10:44:56-06:00
New Revision: 1c6ec29b6bf86709384049660c69cc2d31e356b2

URL: https://github.com/llvm/llvm-project/commit/1c6ec29b6bf86709384049660c69cc2d31e356b2
DIFF: https://github.com/llvm/llvm-project/commit/1c6ec29b6bf86709384049660c69cc2d31e356b2.diff

LOG: [flang][OpenMP] Parsing support for iterator modifiers in FROM and TO (#114593)

Parse PRESENT modifier as well while we're at it (no MAPPER though). Add
semantic checks for these clauses in the TARGET UPDATE construct, TODO
messages in lowering.

Added: 
    flang/test/Lower/OpenMP/Todo/from-expectation-modifier.f90
    flang/test/Lower/OpenMP/Todo/from-iterator-modifier.f90
    flang/test/Lower/OpenMP/Todo/to-expectation-modifier.f90
    flang/test/Lower/OpenMP/Todo/to-iterator-modifier.f90
    flang/test/Parser/OpenMP/declare-target-to-clause.f90
    flang/test/Parser/OpenMP/from-clause.f90
    flang/test/Parser/OpenMP/target-update-to-clause.f90
    flang/test/Semantics/OpenMP/from-clause-v45.f90
    flang/test/Semantics/OpenMP/from-clause-v51.f90
    flang/test/Semantics/OpenMP/to-clause-v45.f90
    flang/test/Semantics/OpenMP/to-clause-v51.f90

Modified: 
    flang/include/flang/Evaluate/check-expression.h
    flang/include/flang/Parser/dump-parse-tree.h
    flang/include/flang/Parser/parse-tree.h
    flang/lib/Lower/OpenMP/ClauseProcessor.cpp
    flang/lib/Lower/OpenMP/Clauses.cpp
    flang/lib/Parser/openmp-parsers.cpp
    flang/lib/Parser/unparse.cpp
    flang/lib/Semantics/check-omp-structure.cpp
    flang/lib/Semantics/check-omp-structure.h
    flang/lib/Semantics/resolve-directives.cpp
    llvm/include/llvm/Frontend/OpenMP/OMP.td

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Evaluate/check-expression.h b/flang/include/flang/Evaluate/check-expression.h
index b711d289ba5246..49b64468ffaa77 100644
--- a/flang/include/flang/Evaluate/check-expression.h
+++ b/flang/include/flang/Evaluate/check-expression.h
@@ -115,6 +115,10 @@ extern template std::optional<bool> IsContiguous(
     const CoarrayRef &, FoldingContext &);
 extern template std::optional<bool> IsContiguous(
     const Symbol &, FoldingContext &);
+static inline std::optional<bool> IsContiguous(
+    const SymbolRef &s, FoldingContext &c) {
+  return IsContiguous(s.get(), c);
+}
 template <typename A>
 bool IsSimplyContiguous(const A &x, FoldingContext &context) {
   return IsContiguous(x, context).value_or(false);

diff  --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h
index 9bd88dceab271f..bfeb23de535392 100644
--- a/flang/include/flang/Parser/dump-parse-tree.h
+++ b/flang/include/flang/Parser/dump-parse-tree.h
@@ -525,6 +525,8 @@ class ParseTreeDumper {
   NODE(parser, OmpEndCriticalDirective)
   NODE(parser, OmpEndLoopDirective)
   NODE(parser, OmpEndSectionsDirective)
+  NODE(parser, OmpFromClause)
+  NODE_ENUM(OmpFromClause, Expectation)
   NODE(parser, OmpIfClause)
   NODE_ENUM(OmpIfClause, DirectiveNameModifier)
   NODE_ENUM(OmpLastprivateClause, LastprivateModifier)
@@ -582,6 +584,9 @@ class ParseTreeDumper {
   NODE(parser, OmpSectionBlocks)
   NODE(parser, OmpSectionsDirective)
   NODE(parser, OmpSimpleStandaloneDirective)
+  NODE(parser, OmpToClause)
+  // No NODE_ENUM for OmpToClause::Expectation, because it's an alias
+  // for OmpFromClause::Expectation.
   NODE(parser, Only)
   NODE(parser, OpenACCAtomicConstruct)
   NODE(parser, OpenACCBlockConstruct)

diff  --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index 6456edca636ddf..2f66aade32ac6e 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -3582,6 +3582,26 @@ struct OmpDeviceTypeClause {
   WRAPPER_CLASS_BOILERPLATE(OmpDeviceTypeClause, Type);
 };
 
+// Ref: [4.5:107-109], [5.0:176-180], [5.1:205-210], [5.2:167-168]
+//
+// from-clause ->
+//    FROM(locator-list) |
+//    FROM(mapper-modifier: locator-list) |             // since 5.0
+//    FROM(motion-modifier[,] ...: locator-list)        // since 5.1
+//  motion-modifier ->
+//    PRESENT | mapper-modifier | iterator-modifier
+struct OmpFromClause {
+  ENUM_CLASS(Expectation, Present);
+  TUPLE_CLASS_BOILERPLATE(OmpFromClause);
+
+  // As in the case of MAP, modifiers are parsed as lists, even if they
+  // are unique. These restrictions will be checked in semantic checks.
+  std::tuple<std::optional<std::list<Expectation>>,
+      std::optional<std::list<OmpIteratorModifier>>, OmpObjectList,
+      bool> // were the modifiers comma-separated?
+      t;
+};
+
 // OMP 5.2 12.6.1 grainsize-clause -> grainsize ([prescriptiveness :] value)
 struct OmpGrainsizeClause {
   TUPLE_CLASS_BOILERPLATE(OmpGrainsizeClause);
@@ -3723,6 +3743,28 @@ struct OmpScheduleClause {
       t;
 };
 
+// Ref: [4.5:107-109], [5.0:176-180], [5.1:205-210], [5.2:167-168]
+//
+// to-clause (in DECLARE TARGET) ->
+//    TO(extended-list) |                               // until 5.1
+// to-clause (in TARGET UPDATE) ->
+//    TO(locator-list) |
+//    TO(mapper-modifier: locator-list) |               // since 5.0
+//    TO(motion-modifier[,] ...: locator-list)          // since 5.1
+//  motion-modifier ->
+//    PRESENT | mapper-modifier | iterator-modifier
+struct OmpToClause {
+  using Expectation = OmpFromClause::Expectation;
+  TUPLE_CLASS_BOILERPLATE(OmpToClause);
+
+  // As in the case of MAP, modifiers are parsed as lists, even if they
+  // are unique. These restrictions will be checked in semantic checks.
+  std::tuple<std::optional<std::list<Expectation>>,
+      std::optional<std::list<OmpIteratorModifier>>, OmpObjectList,
+      bool> // were the modifiers comma-separated?
+      t;
+};
+
 // OMP 5.2 12.6.2 num_tasks-clause -> num_tasks ([prescriptiveness :] value)
 struct OmpNumTasksClause {
   TUPLE_CLASS_BOILERPLATE(OmpNumTasksClause);

diff  --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
index 8eb1fdb4709178..213b6501c077fa 100644
--- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
+++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
@@ -1019,16 +1019,22 @@ bool ClauseProcessor::processMotionClauses(lower::StatementContext &stmtCtx,
 
   auto callbackFn = [&](const auto &clause, const parser::CharBlock &source) {
     mlir::Location clauseLocation = converter.genLocation(source);
-
+    const auto &[expectation, mapper, iterator, objects] = clause.t;
     // TODO Support motion modifiers: present, mapper, iterator.
+    if (expectation) {
+      TODO(clauseLocation, "PRESENT modifier is not supported yet");
+    } else if (mapper) {
+      TODO(clauseLocation, "Mapper modifier is not supported yet");
+    } else if (iterator) {
+      TODO(clauseLocation, "Iterator modifier is not supported yet");
+    }
     constexpr llvm::omp::OpenMPOffloadMappingFlags mapTypeBits =
         std::is_same_v<llvm::remove_cvref_t<decltype(clause)>, omp::clause::To>
             ? llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO
             : llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM;
 
-    processMapObjects(stmtCtx, clauseLocation, std::get<ObjectList>(clause.t),
-                      mapTypeBits, parentMemberIndices, result.mapVars,
-                      mapSymbols);
+    processMapObjects(stmtCtx, clauseLocation, objects, mapTypeBits,
+                      parentMemberIndices, result.mapVars, mapSymbols);
   };
 
   bool clauseFound = findRepeatableClause<omp::clause::To>(callbackFn);

diff  --git a/flang/lib/Lower/OpenMP/Clauses.cpp b/flang/lib/Lower/OpenMP/Clauses.cpp
index 16f7fa35bca776..936d0d21997d5a 100644
--- a/flang/lib/Lower/OpenMP/Clauses.cpp
+++ b/flang/lib/Lower/OpenMP/Clauses.cpp
@@ -728,21 +728,51 @@ Firstprivate make(const parser::OmpClause::Firstprivate &inp,
 
 From make(const parser::OmpClause::From &inp,
           semantics::SemanticsContext &semaCtx) {
-  // inp.v -> parser::OmpObjectList
-  return From{{/*Expectation=*/std::nullopt, /*Mapper=*/std::nullopt,
-               /*Iterator=*/std::nullopt,
-               /*LocatorList=*/makeObjects(inp.v, semaCtx)}};
+  // inp.v -> parser::OmpFromClause
+  using wrapped = parser::OmpFromClause;
+
+  CLAUSET_ENUM_CONVERT( //
+      convert, parser::OmpFromClause::Expectation, From::Expectation,
+      // clang-format off
+      MS(Present, Present)
+      // clang-format on
+  );
+
+  auto &t0 = std::get<std::optional<std::list<wrapped::Expectation>>>(inp.v.t);
+  auto &t1 =
+      std::get<std::optional<std::list<parser::OmpIteratorModifier>>>(inp.v.t);
+  auto &t2 = std::get<parser::OmpObjectList>(inp.v.t);
+
+  assert((!t0 || t0->size() == 1) && "Only one expectation modifier allowed");
+  assert((!t1 || t1->size() == 1) && "Only one iterator modifier allowed");
+
+  auto expectation = [&]() -> std::optional<From::Expectation> {
+    if (t0)
+      return convert(t0->front());
+    return std::nullopt;
+  }();
+
+  auto iterator = [&]() -> std::optional<Iterator> {
+    if (t1)
+      return makeIterator(t1->front(), semaCtx);
+    return std::nullopt;
+  }();
+
+  return From{{/*Expectation=*/std::move(expectation), /*Mapper=*/std::nullopt,
+               /*Iterator=*/std::move(iterator),
+               /*LocatorList=*/makeObjects(t2, semaCtx)}};
 }
 
 // Full: empty
 
 Grainsize make(const parser::OmpClause::Grainsize &inp,
-            semantics::SemanticsContext &semaCtx) {
+               semantics::SemanticsContext &semaCtx) {
   // inp.v -> parser::OmpGrainsizeClause
   using wrapped = parser::OmpGrainsizeClause;
 
   CLAUSET_ENUM_CONVERT( //
-      convert, parser::OmpGrainsizeClause::Prescriptiveness, Grainsize::Prescriptiveness,
+      convert, parser::OmpGrainsizeClause::Prescriptiveness,
+      Grainsize::Prescriptiveness,
       // clang-format off
       MS(Strict,   Strict)
       // clang-format on
@@ -1274,10 +1304,39 @@ ThreadLimit make(const parser::OmpClause::ThreadLimit &inp,
 
 To make(const parser::OmpClause::To &inp,
         semantics::SemanticsContext &semaCtx) {
-  // inp.v -> parser::OmpObjectList
-  return To{{/*Expectation=*/std::nullopt, /*Mapper=*/std::nullopt,
-             /*Iterator=*/std::nullopt,
-             /*LocatorList=*/makeObjects(inp.v, semaCtx)}};
+  // inp.v -> parser::OmpToClause
+  using wrapped = parser::OmpToClause;
+
+  CLAUSET_ENUM_CONVERT( //
+      convert, parser::OmpToClause::Expectation, To::Expectation,
+      // clang-format off
+      MS(Present, Present)
+      // clang-format on
+  );
+
+  auto &t0 = std::get<std::optional<std::list<wrapped::Expectation>>>(inp.v.t);
+  auto &t1 =
+      std::get<std::optional<std::list<parser::OmpIteratorModifier>>>(inp.v.t);
+  auto &t2 = std::get<parser::OmpObjectList>(inp.v.t);
+
+  assert((!t0 || t0->size() == 1) && "Only one expectation modifier allowed");
+  assert((!t1 || t1->size() == 1) && "Only one iterator modifier allowed");
+
+  auto expectation = [&]() -> std::optional<To::Expectation> {
+    if (t0)
+      return convert(t0->front());
+    return std::nullopt;
+  }();
+
+  auto iterator = [&]() -> std::optional<Iterator> {
+    if (t1)
+      return makeIterator(t1->front(), semaCtx);
+    return std::nullopt;
+  }();
+
+  return To{{/*Expectation=*/std::move(expectation), /*Mapper=*/std::nullopt,
+             /*Iterator=*/std::move(iterator),
+             /*LocatorList=*/makeObjects(t2, semaCtx)}};
 }
 
 // UnifiedAddress: empty

diff  --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp
index 764e61fbe1bb81..0510b32a4c485e 100644
--- a/flang/lib/Parser/openmp-parsers.cpp
+++ b/flang/lib/Parser/openmp-parsers.cpp
@@ -122,6 +122,40 @@ template <typename Separator> struct MapModifiers {
   const Separator sep_;
 };
 
+// This is almost exactly the same thing as MapModifiers. It has the same
+// issue (it expects modifiers in a specific order), and the fix for that
+// will change how modifiers are parsed. Instead of making this code more
+// generic, make it simple, and generalize after the fix is in place.
+template <typename Separator> struct MotionModifiers {
+  constexpr MotionModifiers(Separator sep) : sep_(sep) {}
+  constexpr MotionModifiers(const MotionModifiers &) = default;
+  constexpr MotionModifiers(MotionModifiers &&) = default;
+
+  // Parsing of mappers if not implemented yet.
+  using ExpParser = Parser<OmpFromClause::Expectation>;
+  using IterParser = Parser<OmpIteratorModifier>;
+  using ModParser = ConcatSeparated<Separator, ExpParser, IterParser>;
+
+  using resultType = typename ModParser::resultType;
+
+  std::optional<resultType> Parse(ParseState &state) const {
+    auto mp{ModParser(sep_, ExpParser{}, IterParser{})};
+    auto mods{mp.Parse(state)};
+    // The ModParser always "succeeds", i.e. even if the input is junk, it
+    // will return a tuple filled with nullopts. If any of the components
+    // is not a nullopt, expect a ":".
+    if (std::apply([](auto &&...opts) { return (... || !!opts); }, *mods)) {
+      if (!attempt(":"_tok).Parse(state)) {
+        return std::nullopt;
+      }
+    }
+    return std::move(mods);
+  }
+
+private:
+  const Separator sep_;
+};
+
 // OpenMP Clauses
 
 // [5.0] 2.1.6 iterator-specifier -> type-declaration-stmt = subscript-triple |
@@ -382,6 +416,31 @@ TYPE_CONTEXT_PARSER("Omp Depend clause"_en_US,
             maybe(Parser<OmpIteratorModifier>{} / ","_tok),
             Parser<OmpTaskDependenceType>{} / ":", Parser<OmpObjectList>{})))
 
+TYPE_PARSER(construct<OmpFromClause::Expectation>(
+    "PRESENT" >> pure(OmpFromClause::Expectation::Present)))
+
+template <typename MotionClause, bool CommasEverywhere>
+static inline MotionClause makeMotionClause(
+    std::tuple<std::optional<std::list<typename MotionClause::Expectation>>,
+        std::optional<std::list<OmpIteratorModifier>>> &&mods,
+    OmpObjectList &&objs) {
+  auto &&[exp, iter] = std::move(mods);
+  return MotionClause(
+      std::move(exp), std::move(iter), std::move(objs), CommasEverywhere);
+}
+
+TYPE_PARSER(construct<OmpFromClause>(
+    applyFunction<OmpFromClause>(makeMotionClause<OmpFromClause, true>,
+        MotionModifiers(","_tok), Parser<OmpObjectList>{}) ||
+    applyFunction<OmpFromClause>(makeMotionClause<OmpFromClause, false>,
+        MotionModifiers(maybe(","_tok)), Parser<OmpObjectList>{})))
+
+TYPE_PARSER(construct<OmpToClause>(
+    applyFunction<OmpToClause>(makeMotionClause<OmpToClause, true>,
+        MotionModifiers(","_tok), Parser<OmpObjectList>{}) ||
+    applyFunction<OmpToClause>(makeMotionClause<OmpToClause, false>,
+        MotionModifiers(maybe(","_tok)), Parser<OmpObjectList>{})))
+
 // 2.15.3.7 LINEAR (linear-list: linear-step)
 //          linear-list -> list | modifier(list)
 //          linear-modifier -> REF | VAL | UVAL
@@ -478,11 +537,11 @@ TYPE_PARSER(
                     parenthesized(scalarIntExpr))) ||
     "FINAL" >> construct<OmpClause>(construct<OmpClause::Final>(
                    parenthesized(scalarLogicalExpr))) ||
-    "FULL" >> construct<OmpClause>(construct<OmpClause::Full>()) ||
     "FIRSTPRIVATE" >> construct<OmpClause>(construct<OmpClause::Firstprivate>(
                           parenthesized(Parser<OmpObjectList>{}))) ||
     "FROM" >> construct<OmpClause>(construct<OmpClause::From>(
-                  parenthesized(Parser<OmpObjectList>{}))) ||
+                  parenthesized(Parser<OmpFromClause>{}))) ||
+    "FULL" >> construct<OmpClause>(construct<OmpClause::Full>()) ||
     "GRAINSIZE" >> construct<OmpClause>(construct<OmpClause::Grainsize>(
                        parenthesized(Parser<OmpGrainsizeClause>{}))) ||
     "HAS_DEVICE_ADDR" >>
@@ -559,7 +618,7 @@ TYPE_PARSER(
     "THREAD_LIMIT" >> construct<OmpClause>(construct<OmpClause::ThreadLimit>(
                           parenthesized(scalarIntExpr))) ||
     "TO" >> construct<OmpClause>(construct<OmpClause::To>(
-                parenthesized(Parser<OmpObjectList>{}))) ||
+                parenthesized(Parser<OmpToClause>{}))) ||
     "USE_DEVICE_PTR" >> construct<OmpClause>(construct<OmpClause::UseDevicePtr>(
                             parenthesized(Parser<OmpObjectList>{}))) ||
     "USE_DEVICE_ADDR" >>

diff  --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp
index 78303dedd3e517..bbb126dcdb6d5e 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -2138,6 +2138,27 @@ class UnparseVisitor {
     Put(",");
     Walk(std::get<std::optional<ScalarIntConstantExpr>>(x.t));
   }
+  void Unparse(const OmpFromClause &x) {
+    auto &expect{
+        std::get<std::optional<std::list<OmpFromClause::Expectation>>>(x.t)};
+    auto &iter{std::get<std::optional<std::list<OmpIteratorModifier>>>(x.t)};
+    bool needComma{false};
+    if (expect) {
+      Walk(*expect);
+      needComma = true;
+    }
+    if (iter) {
+      if (needComma) {
+        Put(", ");
+      }
+      Walk(*iter);
+      needComma = true;
+    }
+    if (needComma) {
+      Put(": ");
+    }
+    Walk(std::get<OmpObjectList>(x.t));
+  }
   void Unparse(const OmpIfClause &x) {
     Walk(std::get<std::optional<OmpIfClause::DirectiveNameModifier>>(x.t), ":");
     Walk(std::get<ScalarLogicalExpr>(x.t));
@@ -2242,6 +2263,27 @@ class UnparseVisitor {
     Walk(":",
         std::get<std::optional<OmpDefaultmapClause::VariableCategory>>(x.t));
   }
+  void Unparse(const OmpToClause &x) {
+    auto &expect{
+        std::get<std::optional<std::list<OmpToClause::Expectation>>>(x.t)};
+    auto &iter{std::get<std::optional<std::list<OmpIteratorModifier>>>(x.t)};
+    bool needComma{false};
+    if (expect) {
+      Walk(*expect);
+      needComma = true;
+    }
+    if (iter) {
+      if (needComma) {
+        Put(", ");
+      }
+      Walk(*iter);
+      needComma = true;
+    }
+    if (needComma) {
+      Put(": ");
+    }
+    Walk(std::get<OmpObjectList>(x.t));
+  }
 #define GEN_FLANG_CLAUSE_UNPARSE
 #include "llvm/Frontend/OpenMP/OMP.inc"
   void Unparse(const OmpLoopDirective &x) {
@@ -2859,6 +2901,7 @@ class UnparseVisitor {
   WALK_NESTED_ENUM(OmpDeviceTypeClause, Type) // OMP DEVICE_TYPE
   WALK_NESTED_ENUM(
       OmpReductionClause, ReductionModifier) // OMP reduction-modifier
+  WALK_NESTED_ENUM(OmpFromClause, Expectation) // OMP motion-expectation
   WALK_NESTED_ENUM(OmpIfClause, DirectiveNameModifier) // OMP directive-modifier
   WALK_NESTED_ENUM(OmpCancelType, Type) // OMP cancel-type
   WALK_NESTED_ENUM(OmpOrderClause, Type) // OMP order-type

diff  --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index c813100b4b16c8..5aca7a3ea851de 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -8,6 +8,7 @@
 
 #include "check-omp-structure.h"
 #include "definable.h"
+#include "flang/Evaluate/check-expression.h"
 #include "flang/Parser/parse-tree.h"
 #include "flang/Semantics/expression.h"
 #include "flang/Semantics/tools.h"
@@ -268,6 +269,57 @@ bool OmpStructureChecker::IsCloselyNestedRegion(const OmpDirectiveSet &set) {
   return false;
 }
 
+namespace {
+struct ContiguousHelper {
+  ContiguousHelper(SemanticsContext &context)
+      : sctx_(context), fctx_(context.foldingContext()) {}
+
+  template <typename Contained>
+  std::optional<bool> Visit(const common::Indirection<Contained> &x) {
+    return Visit(x.value());
+  }
+  template <typename Contained>
+  std::optional<bool> Visit(const common::Reference<Contained> &x) {
+    return Visit(x.get());
+  }
+  template <typename T> std::optional<bool> Visit(const evaluate::Expr<T> &x) {
+    return common::visit([this](auto &&s) { return Visit(s); }, x.u);
+  }
+  template <typename T>
+  std::optional<bool> Visit(const evaluate::Designator<T> &x) {
+    return common::visit(
+        [this](auto &&s) { return evaluate::IsContiguous(s, fctx_); }, x.u);
+  }
+  template <typename T> std::optional<bool> Visit(const T &) {
+    // Everything else.
+    return std::nullopt;
+  }
+
+private:
+  SemanticsContext &sctx_;
+  evaluate::FoldingContext &fctx_;
+};
+} // namespace
+
+std::optional<bool> OmpStructureChecker::IsContiguous(
+    const parser::OmpObject &object) {
+  return common::visit(common::visitors{
+                           [&](const parser::Name &x) {
+                             // Any member of a common block must be contiguous.
+                             return std::optional<bool>{true};
+                           },
+                           [&](const parser::Designator &x) {
+                             evaluate::ExpressionAnalyzer ea{context_};
+                             if (MaybeExpr maybeExpr{ea.Analyze(x)}) {
+                               return ContiguousHelper{context_}.Visit(
+                                   *maybeExpr);
+                             }
+                             return std::optional<bool>{};
+                           },
+                       },
+      object.u);
+}
+
 void OmpStructureChecker::CheckMultipleOccurrence(
     semantics::UnorderedSymbolSet &listVars,
     const std::list<parser::Name> &nameList, const parser::CharBlock &item,
@@ -1466,9 +1518,10 @@ void OmpStructureChecker::Leave(const parser::OpenMPDeclareTargetConstruct &x) {
           common::visitors{
               [&](const parser::OmpClause::To &toClause) {
                 toClauseFound = true;
-                CheckSymbolNames(dir.source, toClause.v);
-                CheckIsVarPartOfAnotherVar(dir.source, toClause.v);
-                CheckThreadprivateOrDeclareTargetVar(toClause.v);
+                auto &objList{std::get<parser::OmpObjectList>(toClause.v.t)};
+                CheckSymbolNames(dir.source, objList);
+                CheckIsVarPartOfAnotherVar(dir.source, objList);
+                CheckThreadprivateOrDeclareTargetVar(objList);
               },
               [&](const parser::OmpClause::Link &linkClause) {
                 CheckSymbolNames(dir.source, linkClause.v);
@@ -1647,21 +1700,25 @@ void OmpStructureChecker::CheckOrderedDependClause(
 }
 
 void OmpStructureChecker::CheckTargetUpdate() {
-  const parser::OmpClause *toClause = FindClause(llvm::omp::Clause::OMPC_to);
-  const parser::OmpClause *fromClause =
-      FindClause(llvm::omp::Clause::OMPC_from);
-  if (!toClause && !fromClause) {
+  const parser::OmpClause *toWrapper{FindClause(llvm::omp::Clause::OMPC_to)};
+  const parser::OmpClause *fromWrapper{
+      FindClause(llvm::omp::Clause::OMPC_from)};
+  if (!toWrapper && !fromWrapper) {
     context_.Say(GetContext().directiveSource,
-        "At least one motion-clause (TO/FROM) must be specified on TARGET UPDATE construct."_err_en_US);
+        "At least one motion-clause (TO/FROM) must be specified on "
+        "TARGET UPDATE construct."_err_en_US);
   }
-  if (toClause && fromClause) {
+  if (toWrapper && fromWrapper) {
     SymbolSourceMap toSymbols, fromSymbols;
+    auto &fromClause{std::get<parser::OmpClause::From>(fromWrapper->u).v};
+    auto &toClause{std::get<parser::OmpClause::To>(toWrapper->u).v};
     GetSymbolsInObjectList(
-        std::get<parser::OmpClause::To>(toClause->u).v, toSymbols);
+        std::get<parser::OmpObjectList>(fromClause.t), fromSymbols);
     GetSymbolsInObjectList(
-        std::get<parser::OmpClause::From>(fromClause->u).v, fromSymbols);
+        std::get<parser::OmpObjectList>(toClause.t), toSymbols);
+
     for (auto &[symbol, source] : toSymbols) {
-      auto fromSymbol = fromSymbols.find(symbol);
+      auto fromSymbol{fromSymbols.find(symbol)};
       if (fromSymbol != fromSymbols.end()) {
         context_.Say(source,
             "A list item ('%s') can only appear in a TO or FROM clause, but not in both."_err_en_US,
@@ -2515,7 +2572,6 @@ CHECK_SIMPLE_CLAUSE(DistSchedule, OMPC_dist_schedule)
 CHECK_SIMPLE_CLAUSE(Exclusive, OMPC_exclusive)
 CHECK_SIMPLE_CLAUSE(Final, OMPC_final)
 CHECK_SIMPLE_CLAUSE(Flush, OMPC_flush)
-CHECK_SIMPLE_CLAUSE(From, OMPC_from)
 CHECK_SIMPLE_CLAUSE(Full, OMPC_full)
 CHECK_SIMPLE_CLAUSE(Grainsize, OMPC_grainsize)
 CHECK_SIMPLE_CLAUSE(Hint, OMPC_hint)
@@ -3689,11 +3745,62 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Enter &x) {
   }
 }
 
+void OmpStructureChecker::Enter(const parser::OmpClause::From &x) {
+  CheckAllowedClause(llvm::omp::Clause::OMPC_from);
+  unsigned version{context_.langOptions().OpenMPVersion};
+  using ExpMod = parser::OmpFromClause::Expectation;
+  using IterMod = parser::OmpIteratorModifier;
+
+  if (auto &expMod{std::get<std::optional<std::list<ExpMod>>>(x.v.t)}) {
+    unsigned allowedInVersion{51};
+    if (version < allowedInVersion) {
+      context_.Say(GetContext().clauseSource,
+          "The PRESENT modifier is not supported in %s, %s"_warn_en_US,
+          ThisVersion(version), TryVersion(allowedInVersion));
+    }
+    if (expMod->size() != 1) {
+      context_.Say(GetContext().clauseSource,
+          "Only one PRESENT modifier is allowed"_err_en_US);
+    }
+  }
+
+  if (auto &iterMod{std::get<std::optional<std::list<IterMod>>>(x.v.t)}) {
+    unsigned allowedInVersion{51};
+    if (version < allowedInVersion) {
+      context_.Say(GetContext().clauseSource,
+          "Iterator modifiers are not supported in %s, %s"_warn_en_US,
+          ThisVersion(version), TryVersion(allowedInVersion));
+    }
+    if (iterMod->size() != 1) {
+      context_.Say(GetContext().clauseSource,
+          "Only one iterator-modifier is allowed"_err_en_US);
+    }
+    CheckIteratorModifier(iterMod->front());
+  }
+
+  const auto &objList{std::get<parser::OmpObjectList>(x.v.t)};
+  SymbolSourceMap symbols;
+  GetSymbolsInObjectList(objList, symbols);
+  for (const auto &[sym, source] : symbols) {
+    if (!IsVariableListItem(*sym)) {
+      context_.SayWithDecl(
+          *sym, source, "'%s' must be a variable"_err_en_US, sym->name());
+    }
+  }
+
+  // Ref: [4.5:109:19]
+  // If a list item is an array section it must specify contiguous storage.
+  if (version <= 45) {
+    for (const parser::OmpObject &object : objList.v) {
+      CheckIfContiguous(object);
+    }
+  }
+}
+
 void OmpStructureChecker::Enter(const parser::OmpClause::To &x) {
   CheckAllowedClause(llvm::omp::Clause::OMPC_to);
-  if (dirContext_.empty()) {
-    return;
-  }
+  unsigned version{context_.langOptions().OpenMPVersion};
+
   // The "to" clause is only allowed on "declare target" (pre-5.1), and
   // "target update". In the former case it can take an extended list item,
   // in the latter a variable (a locator).
@@ -3705,8 +3812,37 @@ void OmpStructureChecker::Enter(const parser::OmpClause::To &x) {
     return;
   }
   assert(GetContext().directive == llvm::omp::OMPD_target_update);
+  using ExpMod = parser::OmpFromClause::Expectation;
+  using IterMod = parser::OmpIteratorModifier;
 
-  const parser::OmpObjectList &objList{x.v};
+  if (auto &expMod{std::get<std::optional<std::list<ExpMod>>>(x.v.t)}) {
+    unsigned allowedInVersion{51};
+    if (version < allowedInVersion) {
+      context_.Say(GetContext().clauseSource,
+          "The PRESENT modifier is not supported in %s, %s"_warn_en_US,
+          ThisVersion(version), TryVersion(allowedInVersion));
+    }
+    if (expMod->size() != 1) {
+      context_.Say(GetContext().clauseSource,
+          "Only one PRESENT modifier is allowed"_err_en_US);
+    }
+  }
+
+  if (auto &iterMod{std::get<std::optional<std::list<IterMod>>>(x.v.t)}) {
+    unsigned allowedInVersion{51};
+    if (version < allowedInVersion) {
+      context_.Say(GetContext().clauseSource,
+          "Iterator modifiers are not supported in %s, %s"_warn_en_US,
+          ThisVersion(version), TryVersion(allowedInVersion));
+    }
+    if (iterMod->size() != 1) {
+      context_.Say(GetContext().clauseSource,
+          "Only one iterator-modifier is allowed"_err_en_US);
+    }
+    CheckIteratorModifier(iterMod->front());
+  }
+
+  const auto &objList{std::get<parser::OmpObjectList>(x.v.t)};
   SymbolSourceMap symbols;
   GetSymbolsInObjectList(objList, symbols);
   for (const auto &[sym, source] : symbols) {
@@ -3715,6 +3851,14 @@ void OmpStructureChecker::Enter(const parser::OmpClause::To &x) {
           *sym, source, "'%s' must be a variable"_err_en_US, sym->name());
     }
   }
+
+  // Ref: [4.5:109:19]
+  // If a list item is an array section it must specify contiguous storage.
+  if (version <= 45) {
+    for (const parser::OmpObject &object : objList.v) {
+      CheckIfContiguous(object);
+    }
+  }
 }
 
 llvm::StringRef OmpStructureChecker::getClauseName(llvm::omp::Clause clause) {
@@ -3981,21 +4125,64 @@ void OmpStructureChecker::CheckWorkshareBlockStmts(
   }
 }
 
+void OmpStructureChecker::CheckIfContiguous(const parser::OmpObject &object) {
+  if (auto contig{IsContiguous(object)}; contig && !*contig) {
+    const parser::Name *name{GetObjectName(object)};
+    assert(name && "Expecting name component");
+    context_.Say(name->source,
+        "Reference to %s must be a contiguous object"_err_en_US,
+        name->ToString());
+  }
+}
+
+namespace {
+struct NameHelper {
+  template <typename T>
+  static const parser::Name *Visit(const common::Indirection<T> &x) {
+    return Visit(x.value());
+  }
+  static const parser::Name *Visit(const parser::Substring &x) {
+    return Visit(std::get<parser::DataRef>(x.t));
+  }
+  static const parser::Name *Visit(const parser::ArrayElement &x) {
+    return Visit(x.base);
+  }
+  static const parser::Name *Visit(const parser::Designator &x) {
+    return common::visit([](auto &&s) { return Visit(s); }, x.u);
+  }
+  static const parser::Name *Visit(const parser::DataRef &x) {
+    return common::visit([](auto &&s) { return Visit(s); }, x.u);
+  }
+  static const parser::Name *Visit(const parser::OmpObject &x) {
+    return common::visit([](auto &&s) { return Visit(s); }, x.u);
+  }
+  template <typename T> static const parser::Name *Visit(T &&) {
+    return nullptr;
+  }
+  static const parser::Name *Visit(const parser::Name &x) { return &x; }
+};
+} // namespace
+
+const parser::Name *OmpStructureChecker::GetObjectName(
+    const parser::OmpObject &object) {
+  return NameHelper::Visit(object);
+}
+
 const parser::OmpObjectList *OmpStructureChecker::GetOmpObjectList(
     const parser::OmpClause &clause) {
 
   // Clauses with OmpObjectList as its data member
   using MemberObjectListClauses = std::tuple<parser::OmpClause::Copyprivate,
-      parser::OmpClause::Copyin, parser::OmpClause::Firstprivate,
-      parser::OmpClause::From, parser::OmpClause::Link,
+      parser::OmpClause::Copyin, parser::OmpClause::Enter,
+      parser::OmpClause::Firstprivate, parser::OmpClause::Link,
       parser::OmpClause::Private, parser::OmpClause::Shared,
-      parser::OmpClause::To, parser::OmpClause::Enter,
       parser::OmpClause::UseDevicePtr, parser::OmpClause::UseDeviceAddr>;
 
   // Clauses with OmpObjectList in the tuple
-  using TupleObjectListClauses = std::tuple<parser::OmpClause::Allocate,
+  using TupleObjectListClauses = std::tuple<parser::OmpClause::Aligned,
+      parser::OmpClause::Allocate, parser::OmpClause::From,
       parser::OmpClause::Lastprivate, parser::OmpClause::Map,
-      parser::OmpClause::Reduction, parser::OmpClause::Aligned>;
+      parser::OmpClause::Reduction, parser::OmpClause::To>;
 
   // TODO:: Generate the tuples using TableGen.
   // Handle other constructs with OmpObjectList such as OpenMPThreadprivate.

diff  --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index d5fd558cea2372..5e268279347962 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -138,6 +138,7 @@ class OmpStructureChecker
   bool CheckAllowedClause(llvmOmpClause clause);
   bool IsVariableListItem(const Symbol &sym);
   bool IsExtendedListItem(const Symbol &sym);
+  std::optional<bool> IsContiguous(const parser::OmpObject &object);
   void CheckMultipleOccurrence(semantics::UnorderedSymbolSet &listVars,
       const std::list<parser::Name> &nameList, const parser::CharBlock &item,
       const std::string &clauseName);
@@ -221,6 +222,8 @@ class OmpStructureChecker
       const parser::Name &name, const llvm::omp::Clause clause);
   void CheckSharedBindingInOuterContext(
       const parser::OmpObjectList &ompObjectList);
+  void CheckIfContiguous(const parser::OmpObject &object);
+  const parser::Name *GetObjectName(const parser::OmpObject &object);
   const parser::OmpObjectList *GetOmpObjectList(const parser::OmpClause &);
   void CheckPredefinedAllocatorRestriction(const parser::CharBlock &source,
       const parser::OmpObjectList &ompObjectList);

diff  --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index 359dac911b8c7c..c2b5b9673239b9 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -1930,7 +1930,8 @@ bool OmpAttributeVisitor::Pre(const parser::OpenMPDeclareTargetConstruct &x) {
                  parser::Unwrap<parser::OmpClauseList>(spec.u)}) {
     for (const auto &clause : clauseList->v) {
       if (const auto *toClause{std::get_if<parser::OmpClause::To>(&clause.u)}) {
-        ResolveOmpObjectList(toClause->v, Symbol::Flag::OmpDeclareTarget);
+        auto &objList{std::get<parser::OmpObjectList>(toClause->v.t)};
+        ResolveOmpObjectList(objList, Symbol::Flag::OmpDeclareTarget);
       } else if (const auto *linkClause{
                      std::get_if<parser::OmpClause::Link>(&clause.u)}) {
         ResolveOmpObjectList(linkClause->v, Symbol::Flag::OmpDeclareTarget);

diff  --git a/flang/test/Lower/OpenMP/Todo/from-expectation-modifier.f90 b/flang/test/Lower/OpenMP/Todo/from-expectation-modifier.f90
new file mode 100644
index 00000000000000..7be70ba9102e1d
--- /dev/null
+++ b/flang/test/Lower/OpenMP/Todo/from-expectation-modifier.f90
@@ -0,0 +1,8 @@
+!RUN: %not_todo_cmd bbc -emit-hlfir -fopenmp -fopenmp-version=52 -o - %s 2>&1 | FileCheck %s
+!RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=52 -o - %s 2>&1 | FileCheck %s
+
+!CHECK: not yet implemented: PRESENT modifier is not supported yet
+subroutine f00(x)
+  integer :: x
+  !$omp target update from(present: x)
+end

diff  --git a/flang/test/Lower/OpenMP/Todo/from-iterator-modifier.f90 b/flang/test/Lower/OpenMP/Todo/from-iterator-modifier.f90
new file mode 100644
index 00000000000000..973d1d1d76ba48
--- /dev/null
+++ b/flang/test/Lower/OpenMP/Todo/from-iterator-modifier.f90
@@ -0,0 +1,8 @@
+!RUN: %not_todo_cmd bbc -emit-hlfir -fopenmp -fopenmp-version=52 -o - %s 2>&1 | FileCheck %s
+!RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=52 -o - %s 2>&1 | FileCheck %s
+
+!CHECK: not yet implemented: Iterator modifier is not supported yet
+subroutine f00(x)
+  integer :: x(10)
+  !$omp target update from(iterator(i = 1:2): x(i))
+end

diff  --git a/flang/test/Lower/OpenMP/Todo/to-expectation-modifier.f90 b/flang/test/Lower/OpenMP/Todo/to-expectation-modifier.f90
new file mode 100644
index 00000000000000..f29fb8fffb1eb3
--- /dev/null
+++ b/flang/test/Lower/OpenMP/Todo/to-expectation-modifier.f90
@@ -0,0 +1,8 @@
+!RUN: %not_todo_cmd bbc -emit-hlfir -fopenmp -fopenmp-version=52 -o - %s 2>&1 | FileCheck %s
+!RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=52 -o - %s 2>&1 | FileCheck %s
+
+!CHECK: not yet implemented: PRESENT modifier is not supported yet
+subroutine f00(x)
+  integer :: x
+  !$omp target update to(present: x)
+end

diff  --git a/flang/test/Lower/OpenMP/Todo/to-iterator-modifier.f90 b/flang/test/Lower/OpenMP/Todo/to-iterator-modifier.f90
new file mode 100644
index 00000000000000..a587373bf183a7
--- /dev/null
+++ b/flang/test/Lower/OpenMP/Todo/to-iterator-modifier.f90
@@ -0,0 +1,8 @@
+!RUN: %not_todo_cmd bbc -emit-hlfir -fopenmp -fopenmp-version=52 -o - %s 2>&1 | FileCheck %s
+!RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=52 -o - %s 2>&1 | FileCheck %s
+
+!CHECK: not yet implemented: Iterator modifier is not supported yet
+subroutine f00(x)
+  integer :: x(10)
+  !$omp target update to(iterator(i = 1:2): x(i))
+end

diff  --git a/flang/test/Parser/OpenMP/declare-target-to-clause.f90 b/flang/test/Parser/OpenMP/declare-target-to-clause.f90
new file mode 100644
index 00000000000000..bcb23f821e403c
--- /dev/null
+++ b/flang/test/Parser/OpenMP/declare-target-to-clause.f90
@@ -0,0 +1,19 @@
+!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
+
+module m
+  integer :: x, y
+
+  !$omp declare target to(x, y)
+end
+
+!UNPARSE: MODULE m
+!UNPARSE:  INTEGER x, y
+!UNPARSE: !$OMP DECLARE TARGET  TO(x,y)
+!UNPARSE: END MODULE
+
+!PARSE-TREE: OmpDeclareTargetSpecifier -> OmpDeclareTargetWithClause -> OmpClauseList -> OmpClause -> To -> OmpToClause
+!PARSE-TREE: | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
+!PARSE-TREE: | OmpObject -> Designator -> DataRef -> Name = 'y'
+!PARSE-TREE: | bool = 'true'
+

diff  --git a/flang/test/Parser/OpenMP/from-clause.f90 b/flang/test/Parser/OpenMP/from-clause.f90
new file mode 100644
index 00000000000000..1dcca0b611dfb2
--- /dev/null
+++ b/flang/test/Parser/OpenMP/from-clause.f90
@@ -0,0 +1,91 @@
+!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
+  !$omp target update from(x)
+end
+
+!UNPARSE: SUBROUTINE f00 (x)
+!UNPARSE:  INTEGER x
+!UNPARSE: !$OMP TARGET UPDATE  FROM(x)
+!UNPARSE: END SUBROUTINE
+
+!PARSE-TREE: OmpSimpleStandaloneDirective -> llvm::omp::Directive = target update
+!PARSE-TREE: OmpClauseList -> OmpClause -> From -> OmpFromClause
+!PARSE-TREE: | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
+!PARSE-TREE: | bool = 'true'
+
+subroutine f01(x)
+  integer :: x
+  !$omp target update from(present: x)
+end
+
+!UNPARSE: SUBROUTINE f01 (x)
+!UNPARSE:  INTEGER x
+!UNPARSE: !$OMP TARGET UPDATE  FROM(PRESENT: x)
+!UNPARSE: END SUBROUTINE
+
+!PARSE-TREE: OmpSimpleStandaloneDirective -> llvm::omp::Directive = target update
+!PARSE-TREE: OmpClauseList -> OmpClause -> From -> OmpFromClause
+!PARSE-TREE: | Expectation = Present
+!PARSE-TREE: | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
+!PARSE-TREE: | bool = 'true'
+
+subroutine f02(x)
+  integer :: x(10)
+  !$omp target update from(present iterator(i = 1:10): x(i))
+end
+
+!UNPARSE: SUBROUTINE f02 (x)
+!UNPARSE:  INTEGER x(10_4)
+!UNPARSE: !$OMP TARGET UPDATE  FROM(PRESENT, ITERATOR(INTEGER i = 1_4:10_4): x(i))
+!UNPARSE: END SUBROUTINE
+
+!PARSE-TREE: OmpSimpleStandaloneDirective -> llvm::omp::Directive = target update
+!PARSE-TREE: OmpClauseList -> OmpClause -> From -> OmpFromClause
+!PARSE-TREE: | Expectation = Present
+!PARSE-TREE: | OmpIteratorModifier -> OmpIteratorSpecifier
+!PARSE-TREE: | | TypeDeclarationStmt
+!PARSE-TREE: | | | DeclarationTypeSpec -> IntrinsicTypeSpec -> IntegerTypeSpec ->
+!PARSE-TREE: | | | EntityDecl
+!PARSE-TREE: | | | | Name = 'i'
+!PARSE-TREE: | | SubscriptTriplet
+!PARSE-TREE: | | | Scalar -> Integer -> Expr = '1_4'
+!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '1'
+!PARSE-TREE: | | | Scalar -> Integer -> Expr = '10_4'
+!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '10'
+!PARSE-TREE: | OmpObjectList -> OmpObject -> Designator -> DataRef -> ArrayElement
+!PARSE-TREE: | | DataRef -> Name = 'x'
+!PARSE-TREE: | | SectionSubscript -> Integer -> Expr = 'i'
+!PARSE-TREE: | | | Designator -> DataRef -> Name = 'i'
+!PARSE-TREE: | bool = 'false'
+
+subroutine f03(x)
+  integer :: x(10)
+  !$omp target update from(present, iterator(i = 1:10): x(i))
+end
+
+!UNPARSE: SUBROUTINE f03 (x)
+!UNPARSE:  INTEGER x(10_4)
+!UNPARSE: !$OMP TARGET UPDATE  FROM(PRESENT, ITERATOR(INTEGER i = 1_4:10_4): x(i))
+!UNPARSE: END SUBROUTINE
+
+!PARSE-TREE: OmpSimpleStandaloneDirective -> llvm::omp::Directive = target update
+!PARSE-TREE: OmpClauseList -> OmpClause -> From -> OmpFromClause
+!PARSE-TREE: | Expectation = Present
+!PARSE-TREE: | OmpIteratorModifier -> OmpIteratorSpecifier
+!PARSE-TREE: | | TypeDeclarationStmt
+!PARSE-TREE: | | | DeclarationTypeSpec -> IntrinsicTypeSpec -> IntegerTypeSpec ->
+!PARSE-TREE: | | | EntityDecl
+!PARSE-TREE: | | | | Name = 'i'
+!PARSE-TREE: | | SubscriptTriplet
+!PARSE-TREE: | | | Scalar -> Integer -> Expr = '1_4'
+!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '1'
+!PARSE-TREE: | | | Scalar -> Integer -> Expr = '10_4'
+!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '10'
+!PARSE-TREE: | OmpObjectList -> OmpObject -> Designator -> DataRef -> ArrayElement
+!PARSE-TREE: | | DataRef -> Name = 'x'
+!PARSE-TREE: | | SectionSubscript -> Integer -> Expr = 'i'
+!PARSE-TREE: | | | Designator -> DataRef -> Name = 'i'
+!PARSE-TREE: | bool = 'true'

diff  --git a/flang/test/Parser/OpenMP/target-update-to-clause.f90 b/flang/test/Parser/OpenMP/target-update-to-clause.f90
new file mode 100644
index 00000000000000..2702575847924b
--- /dev/null
+++ b/flang/test/Parser/OpenMP/target-update-to-clause.f90
@@ -0,0 +1,91 @@
+!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
+  !$omp target update to(x)
+end
+
+!UNPARSE: SUBROUTINE f00 (x)
+!UNPARSE:  INTEGER x
+!UNPARSE: !$OMP TARGET UPDATE  TO(x)
+!UNPARSE: END SUBROUTINE
+
+!PARSE-TREE: OmpSimpleStandaloneDirective -> llvm::omp::Directive = target update
+!PARSE-TREE: OmpClauseList -> OmpClause -> To -> OmpToClause
+!PARSE-TREE: | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
+!PARSE-TREE: | bool = 'true'
+
+subroutine f01(x)
+  integer :: x
+  !$omp target update to(present: x)
+end
+
+!UNPARSE: SUBROUTINE f01 (x)
+!UNPARSE:  INTEGER x
+!UNPARSE: !$OMP TARGET UPDATE  TO(PRESENT: x)
+!UNPARSE: END SUBROUTINE
+
+!PARSE-TREE: OmpSimpleStandaloneDirective -> llvm::omp::Directive = target update
+!PARSE-TREE: OmpClauseList -> OmpClause -> To -> OmpToClause
+!PARSE-TREE: | Expectation = Present
+!PARSE-TREE: | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
+!PARSE-TREE: | bool = 'true'
+
+subroutine f02(x)
+  integer :: x(10)
+  !$omp target update to(present iterator(i = 1:10): x(i))
+end
+
+!UNPARSE: SUBROUTINE f02 (x)
+!UNPARSE:  INTEGER x(10_4)
+!UNPARSE: !$OMP TARGET UPDATE  TO(PRESENT, ITERATOR(INTEGER i = 1_4:10_4): x(i))
+!UNPARSE: END SUBROUTINE
+
+!PARSE-TREE: OmpSimpleStandaloneDirective -> llvm::omp::Directive = target update
+!PARSE-TREE: OmpClauseList -> OmpClause -> To -> OmpToClause
+!PARSE-TREE: | Expectation = Present
+!PARSE-TREE: | OmpIteratorModifier -> OmpIteratorSpecifier
+!PARSE-TREE: | | TypeDeclarationStmt
+!PARSE-TREE: | | | DeclarationTypeSpec -> IntrinsicTypeSpec -> IntegerTypeSpec ->
+!PARSE-TREE: | | | EntityDecl
+!PARSE-TREE: | | | | Name = 'i'
+!PARSE-TREE: | | SubscriptTriplet
+!PARSE-TREE: | | | Scalar -> Integer -> Expr = '1_4'
+!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '1'
+!PARSE-TREE: | | | Scalar -> Integer -> Expr = '10_4'
+!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '10'
+!PARSE-TREE: | OmpObjectList -> OmpObject -> Designator -> DataRef -> ArrayElement
+!PARSE-TREE: | | DataRef -> Name = 'x'
+!PARSE-TREE: | | SectionSubscript -> Integer -> Expr = 'i'
+!PARSE-TREE: | | | Designator -> DataRef -> Name = 'i'
+!PARSE-TREE: | bool = 'false'
+
+subroutine f03(x)
+  integer :: x(10)
+  !$omp target update to(present, iterator(i = 1:10): x(i))
+end
+
+!UNPARSE: SUBROUTINE f03 (x)
+!UNPARSE:  INTEGER x(10_4)
+!UNPARSE: !$OMP TARGET UPDATE  TO(PRESENT, ITERATOR(INTEGER i = 1_4:10_4): x(i))
+!UNPARSE: END SUBROUTINE
+
+!PARSE-TREE: OmpSimpleStandaloneDirective -> llvm::omp::Directive = target update
+!PARSE-TREE: OmpClauseList -> OmpClause -> To -> OmpToClause
+!PARSE-TREE: | Expectation = Present
+!PARSE-TREE: | OmpIteratorModifier -> OmpIteratorSpecifier
+!PARSE-TREE: | | TypeDeclarationStmt
+!PARSE-TREE: | | | DeclarationTypeSpec -> IntrinsicTypeSpec -> IntegerTypeSpec ->
+!PARSE-TREE: | | | EntityDecl
+!PARSE-TREE: | | | | Name = 'i'
+!PARSE-TREE: | | SubscriptTriplet
+!PARSE-TREE: | | | Scalar -> Integer -> Expr = '1_4'
+!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '1'
+!PARSE-TREE: | | | Scalar -> Integer -> Expr = '10_4'
+!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '10'
+!PARSE-TREE: | OmpObjectList -> OmpObject -> Designator -> DataRef -> ArrayElement
+!PARSE-TREE: | | DataRef -> Name = 'x'
+!PARSE-TREE: | | SectionSubscript -> Integer -> Expr = 'i'
+!PARSE-TREE: | | | Designator -> DataRef -> Name = 'i'
+!PARSE-TREE: | bool = 'true'

diff  --git a/flang/test/Semantics/OpenMP/from-clause-v45.f90 b/flang/test/Semantics/OpenMP/from-clause-v45.f90
new file mode 100644
index 00000000000000..9c418a400e5488
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/from-clause-v45.f90
@@ -0,0 +1,32 @@
+!RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=45
+
+subroutine f00(x)
+  integer :: x(10)
+!ERROR: Reference to x must be a contiguous object
+  !$omp target update from(x(1:10:2))
+end
+
+subroutine f01(x)
+  integer :: x(10)
+!WARNING: Iterator modifiers are not supported in OpenMP v4.5, try -fopenmp-version=51
+  !$omp target update from(iterator(i = 1:5): x(i))
+end
+
+subroutine f02(x)
+  integer :: x(10)
+!WARNING: The PRESENT modifier is not supported in OpenMP v4.5, try -fopenmp-version=51
+!WARNING: Iterator modifiers are not supported in OpenMP v4.5, try -fopenmp-version=51
+  !$omp target update from(present, iterator(i = 1:5): x(i))
+end
+
+subroutine f03(x)
+  integer :: x(10)
+!WARNING: The PRESENT modifier is not supported in OpenMP v4.5, try -fopenmp-version=51
+!ERROR: Only one PRESENT modifier is allowed
+  !$omp target update from(present, present: x)
+end
+
+subroutine f04
+!ERROR: 'f04' must be a variable
+  !$omp target update from(f04)
+end

diff  --git a/flang/test/Semantics/OpenMP/from-clause-v51.f90 b/flang/test/Semantics/OpenMP/from-clause-v51.f90
new file mode 100644
index 00000000000000..18139f04c35cf0
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/from-clause-v51.f90
@@ -0,0 +1,18 @@
+!RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=51
+
+subroutine f01(x)
+  integer :: x(10)
+!ERROR: Only one iterator-modifier is allowed
+  !$omp target update from(iterator(i = 1:5), iterator(j = 1:5): x(i + j))
+end
+
+subroutine f03(x)
+  integer :: x(10)
+!ERROR: Only one PRESENT modifier is allowed
+  !$omp target update from(present, present: x)
+end
+
+subroutine f04
+!ERROR: 'f04' must be a variable
+  !$omp target update from(f04)
+end

diff  --git a/flang/test/Semantics/OpenMP/to-clause-v45.f90 b/flang/test/Semantics/OpenMP/to-clause-v45.f90
new file mode 100644
index 00000000000000..39e842492ef084
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/to-clause-v45.f90
@@ -0,0 +1,32 @@
+!RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=45
+
+subroutine f00(x)
+  integer :: x(10)
+!ERROR: Reference to x must be a contiguous object
+  !$omp target update to(x(1:10:2))
+end
+
+subroutine f01(x)
+  integer :: x(10)
+!WARNING: Iterator modifiers are not supported in OpenMP v4.5, try -fopenmp-version=51
+  !$omp target update to(iterator(i = 1:5): x(i))
+end
+
+subroutine f02(x)
+  integer :: x(10)
+!WARNING: The PRESENT modifier is not supported in OpenMP v4.5, try -fopenmp-version=51
+!WARNING: Iterator modifiers are not supported in OpenMP v4.5, try -fopenmp-version=51
+  !$omp target update to(present, iterator(i = 1:5): x(i))
+end
+
+subroutine f03(x)
+  integer :: x(10)
+!WARNING: The PRESENT modifier is not supported in OpenMP v4.5, try -fopenmp-version=51
+!ERROR: Only one PRESENT modifier is allowed
+  !$omp target update to(present, present: x)
+end
+
+subroutine f04
+!ERROR: 'f04' must be a variable
+  !$omp target update to(f04)
+end

diff  --git a/flang/test/Semantics/OpenMP/to-clause-v51.f90 b/flang/test/Semantics/OpenMP/to-clause-v51.f90
new file mode 100644
index 00000000000000..d4f5f15efeb973
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/to-clause-v51.f90
@@ -0,0 +1,18 @@
+!RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=51
+
+subroutine f01(x)
+  integer :: x(10)
+!ERROR: Only one iterator-modifier is allowed
+  !$omp target update to(iterator(i = 1:5), iterator(j = 1:5): x(i + j))
+end
+
+subroutine f03(x)
+  integer :: x(10)
+!ERROR: Only one PRESENT modifier is allowed
+  !$omp target update to(present, present: x)
+end
+
+subroutine f04
+!ERROR: 'f04' must be a variable
+  !$omp target update to(f04)
+end

diff  --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td
index 0d237aafc94814..36834939d9b451 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMP.td
+++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td
@@ -182,7 +182,7 @@ def OMPC_Flush : Clause<"flush"> {
 }
 def OMPC_From : Clause<"from"> {
   let clangClass = "OMPFromClause";
-  let flangClass = "OmpObjectList";
+  let flangClass = "OmpFromClause";
 }
 def OMPC_Full: Clause<"full"> {
   let clangClass = "OMPFullClause";
@@ -463,7 +463,7 @@ def OMPC_Threads : Clause<"threads"> {
 }
 def OMPC_To : Clause<"to"> {
   let clangClass = "OMPToClause";
-  let flangClass = "OmpObjectList";
+  let flangClass = "OmpToClause";
 }
 def OMPC_UnifiedAddress : Clause<"unified_address"> {
   let clangClass = "OMPUnifiedAddressClause";


        


More information about the flang-commits mailing list