Skip to content

[flang][OpenMP] Use 'present-modifier' instead of 'expectation' in 5.1 - #214083

Merged
kparzysz merged 3 commits into
mainfrom
users/kparzysz/m02-present-modifier
Aug 5, 2026
Merged

[flang][OpenMP] Use 'present-modifier' instead of 'expectation' in 5.1#214083
kparzysz merged 3 commits into
mainfrom
users/kparzysz/m02-present-modifier

Conversation

@kparzysz

@kparzysz kparzysz commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

The 5.1 spec lists PRESENT as an alternative in a 'motion-modifier'. The other alternatives are mapper and iterator. These already exist as separate modifiers, so 'motion-modifier' would best be expressed as a modifier group. While modifier groups are not implemented yet, borrow 'present-modifier' from the 6.0 spec.

The 'expectation' modifier only existed in 5.2, it was replaced by 'present-modifier' in 6.0.

The 5.1 spec lists PRESENT as an alternative in a 'motion-modifier'.
The other alternatives are mapper and iterator. These already exist
as separate modifiers, so 'motion-modifier' would best be expressed
as a modifier group. While modifier groups are not implemented yet,
borrow 'present-modifier' from the 6.0 spec.

The 'expectation' modifier only existed in 5.2, it was replaced by
'present-modifier' in 6.0.
@llvmorg-github-actions

llvmorg-github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown

@llvm/pr-subscribers-flang-fir-hlfir
@llvm/pr-subscribers-flang-openmp

@llvm/pr-subscribers-flang-parser

Author: Krzysztof Parzyszek (kparzysz)

Changes

The 5.1 spec lists PRESENT as an alternative in a 'motion-modifier'. The other alternatives are mapper and iterator. These already exist as separate modifiers, so 'motion-modifier' would best be expressed as a modifier group. While modifier groups are not implemented yet, borrow 'present-modifier' from the 6.0 spec.

The 'expectation' modifier only existed in 5.2, it was replaced by 'present-modifier' in 6.0.


Full diff: https://github.com/llvm/llvm-project/pull/214083.diff

8 Files Affected:

  • (modified) flang/include/flang/Parser/parse-tree.h (+32-16)
  • (modified) flang/lib/Lower/OpenMP/Clauses.cpp (+48-24)
  • (modified) flang/lib/Parser/openmp-parsers.cpp (+21-9)
  • (modified) flang/lib/Semantics/openmp-modifiers.cpp (+6-3)
  • (modified) flang/test/Semantics/OpenMP/from-clause-v45.f90 (+4-4)
  • (modified) flang/test/Semantics/OpenMP/from-clause-v51.f90 (+1-1)
  • (modified) flang/test/Semantics/OpenMP/to-clause-v45.f90 (+4-4)
  • (modified) flang/test/Semantics/OpenMP/to-clause-v51.f90 (+1-1)
diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index d647879c0dc92..6a21d5d8c79d7 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -4292,14 +4292,16 @@ struct OmpPrescriptiveness {
   WRAPPER_CLASS_BOILERPLATE(OmpPrescriptiveness, Value);
 };
 
-// Ref: [4.5:216-219], [5.0:315-324], [5.1:347-355], [5.2:150-158],
-// [6.0:279-288]
+// Ref: [5.1:205-210], [6.0:279-288]
 //
 // present-modifier ->
-//    PRESENT                                       // since 5.1
+//    PRESENT                                       // since 5.1, until 5.1
+//                                                  // since 6.0
 //
-// Until 5.2, it was a part of map-type-modifier. Since 6.0 the
-// map-type-modifier has been split into individual modifiers.
+// In 5.1 it was a part of "motion-modifier" (on FROM and TO clauses), which
+// should really be modeled as a modifier-group. In 5.2 it was replaced by
+// "expectation". It was restored in 6.0 when map-type-modifier was broken up
+// into individual modifiers.
 struct OmpPresentModifier {
   ENUM_CLASS(Value, Present)
   WRAPPER_CLASS_BOILERPLATE(OmpPresentModifier, Value);
@@ -4711,17 +4713,24 @@ struct OmpFailClause {
   WRAPPER_CLASS_BOILERPLATE(OmpFailClause, MemoryOrder);
 };
 
-// Ref: [4.5:107-109], [5.0:176-180], [5.1:205-210], [5.2:167-168]
+// Ref: [4.5:107-109], [5.0:176-180], [5.1:205-210], [5.2:167-168],
+//      [6.0:298-299]
 //
 // from-clause ->
-//    FROM(locator-list) |
-//    FROM(mapper-modifier: locator-list) |         // since 5.0
-//    FROM(motion-modifier[,] ...: locator-list)    // since 5.1
+//    FROM(locator-list) |                          // since 4.5
+//    FROM(modifier[,] ...: locator-list) |         // since 5.0
+// modifier ->
+//    mapper |                                      // since 5.2
+//    motion-modifier |                             // since 5.1, until 5.1
+//    expectation | mapper | iterator               // since 5.2, until 5.2
+//    present-modifier | mapper | iterator |        // since 6.0
+//    directive-name-modifier                       // since 6.0
 //  motion-modifier ->
 //    PRESENT | mapper-modifier | iterator-modifier
 struct OmpFromClause {
   TUPLE_CLASS_BOILERPLATE(OmpFromClause);
-  MODIFIER_BOILERPLATE(OmpExpectation, OmpIterator, OmpMapper);
+  MODIFIER_BOILERPLATE(
+      OmpExpectation, OmpPresentModifier, OmpIterator, OmpMapper);
   std::tuple<MODIFIERS(), OmpObjectList, /*CommaSeparated=*/bool> t;
 };
 
@@ -5070,18 +5079,25 @@ struct OmpThreadsetClause {
 };
 
 // Ref: [4.5:107-109], [5.0:176-180], [5.1:205-210], [5.2:167-168]
+//      [6.0:297-298]
 //
 // to-clause (in DECLARE TARGET) ->
-//    TO(extended-list) |                           // until 5.1
+//    TO(extended-list) |                           // since 4.5, 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 ->
+//    TO(locator-list) |                            // since 4.5
+//    TO(modifier[,] ...: locator-list) |           // since 5.0
+// modifier ->
+//    mapper |                                      // since 5.2
+//    motion-modifier |                             // since 5.1, until 5.1
+//    expectation | mapper | iterator               // since 5.2, until 5.2
+//    present-modifier | mapper | iterator |        // since 6.0
+//    directive-name-modifier                       // since 6.0
+//  motion-modifier ->
 //    PRESENT | mapper-modifier | iterator-modifier
 struct OmpToClause {
   TUPLE_CLASS_BOILERPLATE(OmpToClause);
-  MODIFIER_BOILERPLATE(OmpExpectation, OmpIterator, OmpMapper);
+  MODIFIER_BOILERPLATE(
+      OmpExpectation, OmpPresentModifier, OmpIterator, OmpMapper);
   std::tuple<MODIFIERS(), OmpObjectList, /*CommaSeparated=*/bool> t;
 };
 
diff --git a/flang/lib/Lower/OpenMP/Clauses.cpp b/flang/lib/Lower/OpenMP/Clauses.cpp
index 1b9ce1401118e..a7912ecf6a57b 100644
--- a/flang/lib/Lower/OpenMP/Clauses.cpp
+++ b/flang/lib/Lower/OpenMP/Clauses.cpp
@@ -970,11 +970,17 @@ Firstprivate make(const parser::OmpClause::Firstprivate &inp,
 
 // Flush: empty
 
-From make(const parser::OmpClause::From &inp,
-          semantics::SemanticsContext &semaCtx) {
+From make(
+    const parser::OmpClause::From &inp, semantics::SemanticsContext &semaCtx) {
   // inp.v -> parser::OmpFromClause
   CLAUSET_ENUM_CONVERT( //
-      convert, parser::OmpExpectation::Value, From::Expectation,
+      convertExp, parser::OmpExpectation::Value, From::Expectation,
+      // clang-format off
+      MS(Present, Present)
+      // clang-format on
+  );
+  CLAUSET_ENUM_CONVERT( //
+      convertPre, parser::OmpPresentModifier::Value, From::Expectation,
       // clang-format off
       MS(Present, Present)
       // clang-format on
@@ -982,26 +988,32 @@ From make(const parser::OmpClause::From &inp,
 
   auto &mods = semantics::OmpGetModifiers(inp.v);
   auto *t0 = semantics::OmpGetUniqueModifier<parser::OmpExpectation>(mods);
-  auto *t1 = semantics::OmpGetUniqueModifier<parser::OmpMapper>(mods);
-  auto *t2 = semantics::OmpGetUniqueModifier<parser::OmpIterator>(mods);
-  auto &t3 = std::get<parser::OmpObjectList>(inp.v.t);
+  auto *t1 = semantics::OmpGetUniqueModifier<parser::OmpPresentModifier>(mods);
+  auto *t2 = semantics::OmpGetUniqueModifier<parser::OmpMapper>(mods);
+  auto *t3 = semantics::OmpGetUniqueModifier<parser::OmpIterator>(mods);
+  auto &t4 = std::get<parser::OmpObjectList>(inp.v.t);
+
+  std::optional<From::Expectation> maybeExp = //
+      t0   ? maybeApplyToV(convertExp, t0)
+      : t1 ? maybeApplyToV(convertPre, t1)
+           : std::optional<From::Expectation>{};
 
   auto mappers = [&]() -> std::optional<List<Mapper>> {
-    if (t1)
-      return List<Mapper>{Mapper{makeObject(t1->v, semaCtx)}};
+    if (t2)
+      return List<Mapper>{Mapper{makeObject(t2->v, semaCtx)}};
     return std::nullopt;
   }();
 
   auto iterator = [&]() -> std::optional<Iterator> {
-    if (t2)
-      return makeIterator(*t2, semaCtx);
+    if (t3)
+      return makeIterator(*t3, semaCtx);
     return std::nullopt;
   }();
 
-  return From{{/*Expectation=*/maybeApplyToV(convert, t0),
-               /*Mappers=*/std::move(mappers),
-               /*Iterator=*/std::move(iterator),
-               /*LocatorList=*/makeObjects(t3, semaCtx)}};
+  return From{{/*Expectation=*/maybeExp,
+      /*Mappers=*/std::move(mappers),
+      /*Iterator=*/std::move(iterator),
+      /*LocatorList=*/makeObjects(t4, semaCtx)}};
 }
 
 // Full: empty
@@ -1694,7 +1706,13 @@ To make(const parser::OmpClause::To &inp,
         semantics::SemanticsContext &semaCtx) {
   // inp.v -> parser::OmpToClause
   CLAUSET_ENUM_CONVERT( //
-      convert, parser::OmpExpectation::Value, To::Expectation,
+      convertExp, parser::OmpExpectation::Value, To::Expectation,
+      // clang-format off
+      MS(Present, Present)
+      // clang-format on
+  );
+  CLAUSET_ENUM_CONVERT( //
+      convertPre, parser::OmpPresentModifier::Value, From::Expectation,
       // clang-format off
       MS(Present, Present)
       // clang-format on
@@ -1702,26 +1720,32 @@ To make(const parser::OmpClause::To &inp,
 
   auto &mods = semantics::OmpGetModifiers(inp.v);
   auto *t0 = semantics::OmpGetUniqueModifier<parser::OmpExpectation>(mods);
-  auto *t1 = semantics::OmpGetUniqueModifier<parser::OmpMapper>(mods);
-  auto *t2 = semantics::OmpGetUniqueModifier<parser::OmpIterator>(mods);
-  auto &t3 = std::get<parser::OmpObjectList>(inp.v.t);
+  auto *t1 = semantics::OmpGetUniqueModifier<parser::OmpPresentModifier>(mods);
+  auto *t2 = semantics::OmpGetUniqueModifier<parser::OmpMapper>(mods);
+  auto *t3 = semantics::OmpGetUniqueModifier<parser::OmpIterator>(mods);
+  auto &t4 = std::get<parser::OmpObjectList>(inp.v.t);
+
+  std::optional<From::Expectation> maybeExp = //
+      t0   ? maybeApplyToV(convertExp, t0)
+      : t1 ? maybeApplyToV(convertPre, t1)
+           : std::optional<From::Expectation>{};
 
   auto mappers = [&]() -> std::optional<List<Mapper>> {
-    if (t1)
-      return List<Mapper>{Mapper{makeObject(t1->v, semaCtx)}};
+    if (t2)
+      return List<Mapper>{Mapper{makeObject(t2->v, semaCtx)}};
     return std::nullopt;
   }();
 
   auto iterator = [&]() -> std::optional<Iterator> {
-    if (t2)
-      return makeIterator(*t2, semaCtx);
+    if (t3)
+      return makeIterator(*t3, semaCtx);
     return std::nullopt;
   }();
 
-  return To{{/*Expectation=*/maybeApplyToV(convert, t0),
+  return To{{/*Expectation=*/maybeExp,
              /*Mappers=*/{std::move(mappers)},
              /*Iterator=*/std::move(iterator),
-             /*LocatorList=*/makeObjects(t3, semaCtx)}};
+             /*LocatorList=*/makeObjects(t4, semaCtx)}};
 }
 
 UnifiedAddress make(const parser::OmpClause::UnifiedAddress &inp,
diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp
index ad74cb84aa8bf..7c4e49a673bb0 100644
--- a/flang/lib/Parser/openmp-parsers.cpp
+++ b/flang/lib/Parser/openmp-parsers.cpp
@@ -1088,10 +1088,27 @@ TYPE_PARSER(
 TYPE_PARSER(
     sourced(construct<OmpEnterClause::Modifier>(Parser<OmpAutomapModifier>{})))
 
-TYPE_PARSER(sourced(construct<OmpFromClause::Modifier>(
-    sourced(construct<OmpFromClause::Modifier>(Parser<OmpExpectation>{}) ||
-        construct<OmpFromClause::Modifier>(Parser<OmpMapper>{}) ||
-        construct<OmpFromClause::Modifier>(Parser<OmpIterator>{})))))
+template <typename MotionClause> struct OmpMotionClauseModifierParser {
+  using resultType = typename MotionClause::Modifier;
+
+  std::optional<resultType> Parse(ParseState &state) const {
+    unsigned version{state.userState()->langOptions().OpenMPVersion};
+    if (version == 52) {
+      auto expect{sourced(construct<resultType>(Parser<OmpExpectation>{}))};
+      if (auto &&result{attempt(expect).Parse(state)}) {
+        return std::move(result);
+      }
+    }
+    auto parser{sourced( //
+        construct<resultType>(Parser<OmpPresentModifier>{}) ||
+        construct<resultType>(Parser<OmpMapper>{}) ||
+        construct<resultType>(Parser<OmpIterator>{}))};
+    return parser.Parse(state);
+  }
+};
+
+TYPE_PARSER(OmpMotionClauseModifierParser<OmpFromClause>{})
+TYPE_PARSER(OmpMotionClauseModifierParser<OmpToClause>{})
 
 TYPE_PARSER(sourced(
     construct<OmpGrainsizeClause::Modifier>(Parser<OmpPrescriptiveness>{})))
@@ -1176,11 +1193,6 @@ TYPE_PARSER(sourced(construct<OmpTaskReductionClause::Modifier>(
 TYPE_PARSER(sourced(
     construct<OmpThreadLimitClause::Modifier>(Parser<OmpDimsModifier>{})))
 
-TYPE_PARSER(sourced(construct<OmpToClause::Modifier>(
-    sourced(construct<OmpToClause::Modifier>(Parser<OmpExpectation>{}) ||
-        construct<OmpToClause::Modifier>(Parser<OmpMapper>{}) ||
-        construct<OmpToClause::Modifier>(Parser<OmpIterator>{})))))
-
 TYPE_PARSER(sourced(construct<OmpWhenClause::Modifier>( //
     Parser<OmpContextSelector>{})))
 
diff --git a/flang/lib/Semantics/openmp-modifiers.cpp b/flang/lib/Semantics/openmp-modifiers.cpp
index 972788aff1247..293136d3649ad 100644
--- a/flang/lib/Semantics/openmp-modifiers.cpp
+++ b/flang/lib/Semantics/openmp-modifiers.cpp
@@ -361,11 +361,12 @@ const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpExpectation>() {
       /*name=*/"expectation",
       /*props=*/
       {
-          {51, {OmpProperty::Unique}},
+          {52, {OmpProperty::Unique}},
       },
       /*clauses=*/
       {
-          {51, {Clause::OMPC_from, Clause::OMPC_to}},
+          {52, {Clause::OMPC_from, Clause::OMPC_to}},
+          {60, {}},
       },
   };
   return desc;
@@ -629,7 +630,9 @@ const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpPresentModifier>() {
       },
       /*clauses=*/
       {
-          {51, {Clause::OMPC_map}},
+          {51, {Clause::OMPC_from, Clause::OMPC_to}},
+          {52, {}},
+          {60, {Clause::OMPC_from, Clause::OMPC_map, Clause::OMPC_to}},
       },
   };
   return desc;
diff --git a/flang/test/Semantics/OpenMP/from-clause-v45.f90 b/flang/test/Semantics/OpenMP/from-clause-v45.f90
index 654af4b7dd9b7..284511acfdd59 100644
--- a/flang/test/Semantics/OpenMP/from-clause-v45.f90
+++ b/flang/test/Semantics/OpenMP/from-clause-v45.f90
@@ -14,16 +14,16 @@ subroutine f01(x)
 
 subroutine f02(x)
   integer :: x(10)
-!WARNING: 'expectation' modifier is not supported in OpenMP v4.5, try -fopenmp-version=51
+!WARNING: 'present-modifier' modifier is not supported in OpenMP v4.5, try -fopenmp-version=51
 !WARNING: 'iterator' modifier is 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: 'expectation' modifier is not supported in OpenMP v4.5, try -fopenmp-version=51
-!WARNING: 'expectation' modifier is not supported in OpenMP v4.5, try -fopenmp-version=51
-!ERROR: 'expectation' modifier cannot occur multiple times
+!WARNING: 'present-modifier' modifier is not supported in OpenMP v4.5, try -fopenmp-version=51
+!WARNING: 'present-modifier' modifier is not supported in OpenMP v4.5, try -fopenmp-version=51
+!ERROR: 'present-modifier' modifier cannot occur multiple times
   !$omp target update from(present, present: x)
 end
 
diff --git a/flang/test/Semantics/OpenMP/from-clause-v51.f90 b/flang/test/Semantics/OpenMP/from-clause-v51.f90
index 8771f519fec03..60252a8a1745c 100644
--- a/flang/test/Semantics/OpenMP/from-clause-v51.f90
+++ b/flang/test/Semantics/OpenMP/from-clause-v51.f90
@@ -8,7 +8,7 @@ subroutine f01(x)
 
 subroutine f03(x)
   integer :: x(10)
-!ERROR: 'expectation' modifier cannot occur multiple times
+!ERROR: 'present-modifier' modifier cannot occur multiple times
   !$omp target update from(present, present: x)
 end
 
diff --git a/flang/test/Semantics/OpenMP/to-clause-v45.f90 b/flang/test/Semantics/OpenMP/to-clause-v45.f90
index 7e56817e1ff7c..2fff681d621b1 100644
--- a/flang/test/Semantics/OpenMP/to-clause-v45.f90
+++ b/flang/test/Semantics/OpenMP/to-clause-v45.f90
@@ -14,16 +14,16 @@ subroutine f01(x)
 
 subroutine f02(x)
   integer :: x(10)
-!WARNING: 'expectation' modifier is not supported in OpenMP v4.5, try -fopenmp-version=51
+!WARNING: 'present-modifier' modifier is not supported in OpenMP v4.5, try -fopenmp-version=51
 !WARNING: 'iterator' modifier is 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: 'expectation' modifier is not supported in OpenMP v4.5, try -fopenmp-version=51
-!WARNING: 'expectation' modifier is not supported in OpenMP v4.5, try -fopenmp-version=51
-!ERROR: 'expectation' modifier cannot occur multiple times
+!WARNING: 'present-modifier' modifier is not supported in OpenMP v4.5, try -fopenmp-version=51
+!WARNING: 'present-modifier' modifier is not supported in OpenMP v4.5, try -fopenmp-version=51
+!ERROR: 'present-modifier' modifier cannot occur multiple times
   !$omp target update to(present, present: x)
 end
 
diff --git a/flang/test/Semantics/OpenMP/to-clause-v51.f90 b/flang/test/Semantics/OpenMP/to-clause-v51.f90
index 0db292a22238b..15e742c1ece22 100644
--- a/flang/test/Semantics/OpenMP/to-clause-v51.f90
+++ b/flang/test/Semantics/OpenMP/to-clause-v51.f90
@@ -8,7 +8,7 @@ subroutine f01(x)
 
 subroutine f03(x)
   integer :: x(10)
-!ERROR: 'expectation' modifier cannot occur multiple times
+!ERROR: 'present-modifier' modifier cannot occur multiple times
   !$omp target update to(present, present: x)
 end
 

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown

✅ With the latest revision this PR passed the C/C++ code formatter.

Comment thread flang/lib/Lower/OpenMP/Clauses.cpp Outdated
// clang-format on
);
CLAUSET_ENUM_CONVERT( //
convertPre, parser::OmpPresentModifier::Value, From::Expectation,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should use To::Expectation

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@tblah tblah left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks!

@kparzysz
kparzysz merged commit 53e7088 into main Aug 5, 2026
12 checks passed
@kparzysz
kparzysz deleted the users/kparzysz/m02-present-modifier branch August 5, 2026 13:34
jinge90 pushed a commit to jinge90/llvm-project that referenced this pull request Aug 6, 2026
llvm#214083)

The 5.1 spec lists PRESENT as an alternative in a 'motion-modifier'. The
other alternatives are mapper and iterator. These already exist as
separate modifiers, so 'motion-modifier' would best be expressed as a
modifier group. While modifier groups are not implemented yet, borrow
'present-modifier' from the 6.0 spec.

The 'expectation' modifier only existed in 5.2, it was replaced by
'present-modifier' in 6.0.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants