diff --git a/flang/examples/FeatureList/FeatureList.cpp b/flang/examples/FeatureList/FeatureList.cpp index 7e024dc387516..6ae92acf20608 100644 --- a/flang/examples/FeatureList/FeatureList.cpp +++ b/flang/examples/FeatureList/FeatureList.cpp @@ -498,8 +498,7 @@ struct NodeVisitor { READ_FEATURE(OmpLinearModifier::Value) READ_FEATURE(OmpLoopDirective) READ_FEATURE(OmpMapClause) - READ_FEATURE(OmpMapClause::TypeModifier) - READ_FEATURE(OmpMapClause::Type) + READ_FEATURE(OmpMapClause::Modifier) READ_FEATURE(OmpNumTasksClause) READ_FEATURE(OmpNumTasksClause::Prescriptiveness) READ_FEATURE(OmpObject) diff --git a/flang/examples/FlangOmpReport/FlangOmpReportVisitor.cpp b/flang/examples/FlangOmpReport/FlangOmpReportVisitor.cpp index a3d9b0cfdc79b..5bd8c76199278 100644 --- a/flang/examples/FlangOmpReport/FlangOmpReportVisitor.cpp +++ b/flang/examples/FlangOmpReport/FlangOmpReportVisitor.cpp @@ -229,8 +229,8 @@ void OpenMPCounterVisitor::Post(const OmpTaskDependenceType::Value &c) { clauseDetails += "type=" + std::string{OmpTaskDependenceType::EnumToString(c)} + ";"; } -void OpenMPCounterVisitor::Post(const OmpMapClause::Type &c) { - clauseDetails += "type=" + std::string{OmpMapClause::EnumToString(c)} + ";"; +void OpenMPCounterVisitor::Post(const OmpMapType::Value &c) { + clauseDetails += "type=" + std::string{OmpMapType::EnumToString(c)} + ";"; } void OpenMPCounterVisitor::Post(const OmpScheduleClause::Kind &c) { clauseDetails += diff --git a/flang/examples/FlangOmpReport/FlangOmpReportVisitor.h b/flang/examples/FlangOmpReport/FlangOmpReportVisitor.h index 86f206ba85c6d..7e9ae94bef297 100644 --- a/flang/examples/FlangOmpReport/FlangOmpReportVisitor.h +++ b/flang/examples/FlangOmpReport/FlangOmpReportVisitor.h @@ -75,7 +75,7 @@ struct OpenMPCounterVisitor { void Post(const OmpLinearModifier::Value &c); void Post(const OmpOrderingModifier::Value &c); void Post(const OmpTaskDependenceType::Value &c); - void Post(const OmpMapClause::Type &c); + void Post(const OmpMapType::Value &c); void Post(const OmpScheduleClause::Kind &c); void Post(const OmpIfClause::DirectiveNameModifier &c); void Post(const OmpCancelType::Type &c); diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h index 6d1e7329d5cce..68f9406dc2830 100644 --- a/flang/include/flang/Parser/dump-parse-tree.h +++ b/flang/include/flang/Parser/dump-parse-tree.h @@ -476,6 +476,11 @@ class ParseTreeDumper { NODE(parser, NullInit) NODE(parser, ObjectDecl) NODE(parser, OldParameterStmt) + NODE(parser, OmpMapper) + NODE(parser, OmpMapType) + NODE_ENUM(OmpMapType, Value) + NODE(parser, OmpMapTypeModifier) + NODE_ENUM(OmpMapTypeModifier, Value) NODE(parser, OmpIteratorSpecifier) NODE(parser, OmpIterator) NODE(parser, OmpAffinityClause) @@ -536,7 +541,9 @@ class ParseTreeDumper { NODE(parser, OmpEndLoopDirective) NODE(parser, OmpEndSectionsDirective) NODE(parser, OmpFromClause) - NODE_ENUM(OmpFromClause, Expectation) + NODE(OmpFromClause, Modifier) + NODE(parser, OmpExpectation) + NODE_ENUM(OmpExpectation, Value) NODE(parser, OmpIfClause) NODE_ENUM(OmpIfClause, DirectiveNameModifier) NODE_ENUM(OmpLastprivateClause, LastprivateModifier) @@ -548,9 +555,7 @@ class ParseTreeDumper { NODE_ENUM(OmpLinearModifier, Value) NODE(parser, OmpLoopDirective) NODE(parser, OmpMapClause) - NODE(parser, OmpMapperIdentifier) - NODE_ENUM(OmpMapClause, TypeModifier) - NODE_ENUM(OmpMapClause, Type) + NODE(OmpMapClause, Modifier) static std::string GetNodeName(const llvm::omp::Clause &x) { return llvm::Twine( "llvm::omp::Clause = ", llvm::omp::getOpenMPClauseName(x)) @@ -601,8 +606,7 @@ class ParseTreeDumper { NODE(parser, OmpSectionsDirective) NODE(parser, OmpSimpleStandaloneDirective) NODE(parser, OmpToClause) - // No NODE_ENUM for OmpToClause::Expectation, because it's an alias - // for OmpFromClause::Expectation. + NODE(OmpToClause, Modifier) 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 de179f47be8fc..8d7119a56b7f8 100644 --- a/flang/include/flang/Parser/parse-tree.h +++ b/flang/include/flang/Parser/parse-tree.h @@ -3502,6 +3502,21 @@ struct OmpDependenceType { WRAPPER_CLASS_BOILERPLATE(OmpDependenceType, Value); }; +// Ref: [5.1:205-209], [5.2:166-168] +// +// motion-modifier -> +// PRESENT | // since 5.0, until 5.0 +// mapper | iterator +// expectation -> +// PRESENT // since 5.1 +// +// The PRESENT value was a part of motion-modifier in 5.1, and became a +// value of expectation in 5.2. +struct OmpExpectation { + ENUM_CLASS(Value, Present); + WRAPPER_CLASS_BOILERPLATE(OmpExpectation, Value); +}; + // Ref: [5.0:47-49], [5.1:49-51], [5.2:67-69] // // iterator-modifier -> @@ -3519,6 +3534,34 @@ struct OmpLinearModifier { WRAPPER_CLASS_BOILERPLATE(OmpLinearModifier, Value); }; +// Ref: [5.0:176-180], [5.1:205-210], [5.2:149-150] +// +// mapper -> +// identifier // since 4.5 +struct OmpMapper { + WRAPPER_CLASS_BOILERPLATE(OmpMapper, Name); +}; + +// Ref: [4.5:216-219], [5.0:315-324], [5.1:347-355], [5.2:150-158] +// +// map-type -> +// ALLOC | DELETE | FROM | RELEASE | TO | TOFROM // since 4.5 +struct OmpMapType { + ENUM_CLASS(Value, Alloc, Delete, From, Release, To, Tofrom); + WRAPPER_CLASS_BOILERPLATE(OmpMapType, Value); +}; + +// Ref: [4.5:216-219], [5.0:315-324], [5.1:347-355], [5.2:150-158] +// +// map-type-modifier -> +// ALWAYS | // since 4.5 +// CLOSE | // since 5.0 +// PRESENT // since 5.1 +struct OmpMapTypeModifier { + ENUM_CLASS(Value, Always, Close, Present, Ompx_Hold) + WRAPPER_CLASS_BOILERPLATE(OmpMapTypeModifier, Value); +}; + // Ref: [4.5:56-63], [5.0:101-109], [5.1:126-133], [5.2:252-254] // // modifier -> @@ -3546,10 +3589,10 @@ struct OmpOrderModifier { // Ref: [4.5:201-207], [5.0:293-299], [5.1:325-331], [5.2:124] // // reduction-identifier -> -// base-language-identifier | // since 4.5 -// - | // since 4.5, until 5.2 -// + | * | .AND. | .OR. | .EQV. | .NEQV. | // since 4.5 -// MIN | MAX | IAND | IOR | IEOR // since 4.5 +// base-language-identifier | // since 4.5 +// - | // since 4.5, until 5.2 +// + | * | .AND. | .OR. | .EQV. | .NEQV. | // since 4.5 +// MIN | MAX | IAND | IOR | IEOR // since 4.5 struct OmpReductionIdentifier { UNION_CLASS_BOILERPLATE(OmpReductionIdentifier); std::variant u; @@ -3558,7 +3601,7 @@ struct OmpReductionIdentifier { // Ref: [5.0:300-302], [5.1:332-334], [5.2:134-137] // // reduction-modifier -> -// DEFAULT | INSCAN | TASK // since 5.0 +// DEFAULT | INSCAN | TASK // since 5.0 struct OmpReductionModifier { ENUM_CLASS(Value, Default, Inscan, Task); WRAPPER_CLASS_BOILERPLATE(OmpReductionModifier, Value); @@ -3578,9 +3621,9 @@ struct OmpTaskDependenceType { // Ref: [4.5:229-230], [5.0:324-325], [5.1:357-358], [5.2:161-162] // // variable-category -> -// SCALAR | // since 4.5 -// AGGREGATE | ALLOCATABLE | POINTER | // since 5.0 -// ALL // since 5.2 +// SCALAR | // since 4.5 +// AGGREGATE | ALLOCATABLE | POINTER | // since 5.0 +// ALL // since 5.2 struct OmpVariableCategory { ENUM_CLASS(Value, Aggregate, All, Allocatable, Pointer, Scalar) WRAPPER_CLASS_BOILERPLATE(OmpVariableCategory, Value); @@ -3723,15 +3766,9 @@ struct OmpDeviceTypeClause { // 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>, OmpObjectList, - bool> // were the modifiers comma-separated? - t; + MODIFIER_BOILERPLATE(OmpExpectation, OmpIterator, OmpMapper); + std::tuple t; }; // OMP 5.2 12.6.1 grainsize-clause -> grainsize ([prescriptiveness :] value) @@ -3794,31 +3831,19 @@ struct OmpLinearClause { std::variant u; }; -WRAPPER_CLASS(OmpMapperIdentifier, std::optional); - -// 2.15.5.1 map -> -// MAP ([MAPPER(mapper-identifier)] [[map-type-modifier-list [,]] -// [iterator-modifier [,]] map-type : ] -// variable-name-list) -// map-type-modifier-list -> map-type-modifier [,] [...] -// map-type-modifier -> ALWAYS | CLOSE | PRESENT | OMPX_HOLD -// map-type -> TO | FROM | TOFROM | ALLOC | RELEASE | DELETE +// Ref: [4.5:216-219], [5.0:315-324], [5.1:347-355], [5.2:150-158] +// +// map-clause -> +// MAP([modifier...:] locator-list) // since 4.5 +// modifier -> +// map-type-modifier | // since 4.5 +// mapper | // since 5.0 +// iterator | // since 5.1 +// map-type // since 4.5 struct OmpMapClause { - ENUM_CLASS(TypeModifier, Always, Close, Present, Ompx_Hold); - ENUM_CLASS(Type, To, From, Tofrom, Alloc, Release, Delete) TUPLE_CLASS_BOILERPLATE(OmpMapClause); - - // All modifiers are parsed into optional lists, even if they are unique. - // The checks for satisfying those constraints are deferred to semantics. - // In OpenMP 5.2 the non-comma syntax has been deprecated: keep the - // information about separator presence to emit a diagnostic if needed. - std::tuple>, - std::optional>, // unique - std::optional>, // unique - OmpObjectList, - bool> // were the modifiers comma-separated? - t; + MODIFIER_BOILERPLATE(OmpMapTypeModifier, OmpMapper, OmpIterator, OmpMapType); + std::tuple t; }; // Ref: [5.0:101-109], [5.1:126-134], [5.2:233-234] @@ -3869,23 +3894,17 @@ struct OmpScheduleClause { // 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(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 -> +// 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>, OmpObjectList, - bool> // were the modifiers comma-separated? - t; + MODIFIER_BOILERPLATE(OmpExpectation, OmpIterator, OmpMapper); + std::tuple t; }; // OMP 5.2 12.6.2 num_tasks-clause -> num_tasks ([prescriptiveness :] value) @@ -3897,8 +3916,10 @@ struct OmpNumTasksClause { // Ref: [5.0:254-255], [5.1:287-288], [5.2:321-322] // -// update-clause -> UPDATE(dependence-type) // since 5.0, until 5.1 -// update-clause -> UPDATE(task-dependence-type) // since 5.2 +// 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 u; diff --git a/flang/include/flang/Semantics/openmp-modifiers.h b/flang/include/flang/Semantics/openmp-modifiers.h index beab4c9b46a21..60f116e6f0033 100644 --- a/flang/include/flang/Semantics/openmp-modifiers.h +++ b/flang/include/flang/Semantics/openmp-modifiers.h @@ -10,6 +10,7 @@ #define FORTRAN_SEMANTICS_OPENMP_MODIFIERS_H_ #include "flang/Common/enum-set.h" +#include "flang/Parser/characters.h" #include "flang/Parser/parse-tree.h" #include "flang/Semantics/semantics.h" #include "llvm/ADT/STLExtras.h" @@ -18,6 +19,7 @@ #include #include +#include #include #include @@ -51,6 +53,7 @@ struct OmpModifierDescriptor { // Modifier name for use in diagnostic messages. const OmpProperties &props(unsigned version) const; const OmpClauses &clauses(unsigned version) const; + unsigned since(llvm::omp::Clause id) const; const llvm::StringRef name; // Version-dependent properties of the modifier. @@ -61,26 +64,25 @@ struct OmpModifierDescriptor { template const OmpModifierDescriptor &OmpGetDescriptor(); -template <> -const OmpModifierDescriptor &OmpGetDescriptor(); -template <> -const OmpModifierDescriptor &OmpGetDescriptor(); -template <> -const OmpModifierDescriptor &OmpGetDescriptor(); -template <> -const OmpModifierDescriptor &OmpGetDescriptor(); -template <> -const OmpModifierDescriptor &OmpGetDescriptor(); -template <> -const OmpModifierDescriptor &OmpGetDescriptor(); -template <> -const OmpModifierDescriptor &OmpGetDescriptor(); -template <> -const OmpModifierDescriptor &OmpGetDescriptor(); -template <> -const OmpModifierDescriptor &OmpGetDescriptor(); -template <> -const OmpModifierDescriptor &OmpGetDescriptor(); +#define DECLARE_DESCRIPTOR(name) \ + template <> const OmpModifierDescriptor &OmpGetDescriptor() + +DECLARE_DESCRIPTOR(parser::OmpChunkModifier); +DECLARE_DESCRIPTOR(parser::OmpDependenceType); +DECLARE_DESCRIPTOR(parser::OmpExpectation); +DECLARE_DESCRIPTOR(parser::OmpIterator); +DECLARE_DESCRIPTOR(parser::OmpLinearModifier); +DECLARE_DESCRIPTOR(parser::OmpMapper); +DECLARE_DESCRIPTOR(parser::OmpMapType); +DECLARE_DESCRIPTOR(parser::OmpMapTypeModifier); +DECLARE_DESCRIPTOR(parser::OmpOrderModifier); +DECLARE_DESCRIPTOR(parser::OmpOrderingModifier); +DECLARE_DESCRIPTOR(parser::OmpReductionIdentifier); +DECLARE_DESCRIPTOR(parser::OmpReductionModifier); +DECLARE_DESCRIPTOR(parser::OmpTaskDependenceType); +DECLARE_DESCRIPTOR(parser::OmpVariableCategory); + +#undef DECLARE_DESCRIPTOR // Explanation of terminology: // @@ -94,7 +96,7 @@ const OmpModifierDescriptor &OmpGetDescriptor(); // std::tuple>, ...> t; // }; // -// The Speficic1, etc. refer to parser classes that represent modifiers, +// The Specific1, etc. refer to parser classes that represent modifiers, // e.g. OmpIterator or OmpTaskDependenceType. The Variant type contains // all modifiers that are allowed for a given clause. The Modifier class // is there to wrap the variant into the form that the parse tree visitor @@ -148,39 +150,110 @@ typename std::list::const_iterator findInRange( } } // namespace detail -/// Finds the entry in the list that holds the `SpecificTy` alternative, +/// Finds the first entry in the list that holds the `SpecificTy` alternative, /// and returns the pointer to that alternative. If such an entry does not /// exist, it returns nullptr. -/// The list is assumed to contain at most one such item, with a check -/// whether the condition is met. -/// This function should only be called after the verification of modifier -/// properties has been performed, since it will assert if multiple items -/// are found. template const SpecificTy *OmpGetUniqueModifier( const std::optional> &modifiers) { const SpecificTy *found{nullptr}; if (modifiers) { auto end{modifiers->cend()}; - // typename std::list::iterator end{modifiers->end()}; auto at{detail::findInRange(modifiers->cbegin(), end)}; if (at != end) { found = &std::get(at->u); -#ifndef NDEBUG - auto another{ - detail::findInRange(std::next(at), end)}; - assert(another == end && "repeated modifier"); -#endif } } return found; } +template struct OmpSpecificModifierIterator { + using VectorTy = std::vector; + OmpSpecificModifierIterator( + std::shared_ptr list, typename VectorTy::const_iterator where) + : specificList(list), at(where) {} + + OmpSpecificModifierIterator &operator++() { + ++at; + return *this; + } + // OmpSpecificModifierIterator &operator++(int); + OmpSpecificModifierIterator &operator--() { + --at; + return *this; + } + // OmpSpecificModifierIterator &operator--(int); + + const SpecificTy *operator*() const { return *at; } + bool operator==(const OmpSpecificModifierIterator &other) const { + assert(specificList.get() == other.specificList.get() && + "comparing unrelated iterators"); + return at == other.at; + } + bool operator!=(const OmpSpecificModifierIterator &other) const { + return !(*this == other); + } + +private: + std::shared_ptr specificList; + typename VectorTy::const_iterator at; +}; + +template +llvm::iterator_range> +OmpGetRepeatableModifier(const std::optional> &modifiers) { + using VectorTy = std::vector; + std::shared_ptr items(new VectorTy); + if (modifiers) { + for (auto &m : *modifiers) { + if (auto *s = std::get_if(&m.u)) { + items->push_back(s); + } + } + } + return llvm::iterator_range( + OmpSpecificModifierIterator(items, items->begin()), + OmpSpecificModifierIterator(items, items->end())); +} + +template +llvm::iterator_range> +OmpGetRepeatableModifier(std::optional> &&) = delete; + namespace detail { template constexpr const T *make_nullptr() { return static_cast(nullptr); } +/// Verify that all modifiers are allowed in the given OpenMP version. +template +bool verifyVersions(const std::optional> &modifiers, + llvm::omp::Clause id, parser::CharBlock clauseSource, + SemanticsContext &semaCtx) { + if (!modifiers) { + return true; + } + unsigned version{semaCtx.langOptions().OpenMPVersion}; + bool result{true}; + for (auto &m : *modifiers) { + const OmpModifierDescriptor &desc{OmpGetDescriptor(m)}; + unsigned since{desc.since(id)}; + if (since == ~0u) { + // This shouldn't really happen, but have it just in case. + semaCtx.Say(m.source, + "'%s' modifier is not supported on %s clause"_err_en_US, + desc.name.str(), + parser::ToUpperCaseLetters(llvm::omp::getOpenMPClauseName(id))); + } else if (version < since) { + semaCtx.Say(m.source, + "'%s' modifier is not supported in OpenMP v%d.%d, try -fopenmp-version=%d"_warn_en_US, + desc.name.str(), version / 10, version % 10, since); + result = false; + } + } + return result; +} + /// Helper function for verifying the Required property: /// For a specific SpecificTy, if SpecificTy is has the Required property, /// check if the list has an item that holds SpecificTy as an alternative. @@ -201,7 +274,7 @@ bool verifyIfRequired(const SpecificTy *, }); if (!present) { semaCtx.Say( - clauseSource, "A %s modifier is required"_err_en_US, desc.name.str()); + clauseSource, "'%s' modifier is required"_err_en_US, desc.name.str()); } return present; } @@ -224,7 +297,8 @@ bool verifyRequiredPack(const std::optional> &modifiers, /// list is valid, or false otherwise. template bool verifyRequired(const std::optional> &modifiers, - parser::CharBlock clauseSource, SemanticsContext &semaCtx) { + llvm::omp::Clause id, parser::CharBlock clauseSource, + SemanticsContext &semaCtx) { using VariantTy = typename UnionTy::Variant; return verifyRequiredPack(modifiers, clauseSource, semaCtx, std::make_index_sequence>{}); @@ -253,7 +327,8 @@ bool verifyIfUnique(const SpecificTy *, auto next{ detail::findInRange(std::next(specific), end)}; if (next != end) { - semaCtx.Say(next->source, "A %s cannot occur multiple times"_err_en_US, + semaCtx.Say(next->source, + "'%s' modifier cannot occur multiple times"_err_en_US, desc.name.str()); } } @@ -264,7 +339,8 @@ bool verifyIfUnique(const SpecificTy *, /// list is valid, or false otherwise. template bool verifyUnique(const std::optional> &modifiers, - parser::CharBlock clauseSource, SemanticsContext &semaCtx) { + llvm::omp::Clause id, parser::CharBlock clauseSource, + SemanticsContext &semaCtx) { if (!modifiers) { return true; } @@ -284,7 +360,8 @@ bool verifyUnique(const std::optional> &modifiers, /// list is valid, or false otherwise. template bool verifyUltimate(const std::optional> &modifiers, - parser::CharBlock clauseSource, SemanticsContext &semaCtx) { + llvm::omp::Clause id, parser::CharBlock clauseSource, + SemanticsContext &semaCtx) { if (!modifiers || modifiers->size() <= 1) { return true; } @@ -314,8 +391,8 @@ bool verifyUltimate(const std::optional> &modifiers, } llvm::StringRef where{isPre ? "last" : "first"}; semaCtx.Say(it->source, - "The %s should be the %s modifier"_err_en_US, - desc.name.str(), where.str()); + "'%s' should be the %s modifier"_err_en_US, desc.name.str(), + where.str()); return false; } return true; @@ -330,7 +407,8 @@ bool verifyUltimate(const std::optional> &modifiers, /// list is valid, or false otherwise. template bool verifyExclusive(const std::optional> &modifiers, - parser::CharBlock clauseSource, SemanticsContext &semaCtx) { + llvm::omp::Clause id, parser::CharBlock clauseSource, + SemanticsContext &semaCtx) { if (!modifiers || modifiers->size() <= 1) { return true; } @@ -345,11 +423,11 @@ bool verifyExclusive(const std::optional> &modifiers, const OmpModifierDescriptor &descExcl{OmpGetDescriptor(excl)}; const OmpModifierDescriptor &descOther{OmpGetDescriptor(other)}; parser::MessageFormattedText txt( - "An exclusive %s cannot be specified together with a modifier of a different type"_err_en_US, + "An exclusive '%s' modifier cannot be specified together with a modifier of a different type"_err_en_US, descExcl.name.str()); parser::Message message(excl.source, txt); message.Attach( - other.source, "%s provided here"_en_US, descOther.name.str()); + other.source, "'%s' provided here"_en_US, descOther.name.str()); semaCtx.Say(std::move(message)); }}; @@ -387,14 +465,16 @@ bool verifyExclusive(const std::optional> &modifiers, } // namespace detail template -bool OmpVerifyModifiers(const ClauseTy &clause, parser::CharBlock clauseSource, - SemanticsContext &semaCtx) { +bool OmpVerifyModifiers(const ClauseTy &clause, llvm::omp::Clause id, + parser::CharBlock clauseSource, SemanticsContext &semaCtx) { auto &modifiers{OmpGetModifiers(clause)}; - bool result{detail::verifyRequired(modifiers, clauseSource, semaCtx)}; - result = detail::verifyUnique(modifiers, clauseSource, semaCtx) && result; - result = detail::verifyUltimate(modifiers, clauseSource, semaCtx) && result; - result = detail::verifyExclusive(modifiers, clauseSource, semaCtx) && result; - return result; + bool results[]{// + detail::verifyVersions(modifiers, id, clauseSource, semaCtx), + detail::verifyRequired(modifiers, id, clauseSource, semaCtx), + detail::verifyUnique(modifiers, id, clauseSource, semaCtx), + detail::verifyUltimate(modifiers, id, clauseSource, semaCtx), + detail::verifyExclusive(modifiers, id, clauseSource, semaCtx)}; + return llvm::all_of(results, [](bool x) { return x; }); } } // namespace Fortran::semantics diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp index 0f2e849c2c6a0..6baa22a44eafb 100644 --- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp +++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp @@ -1000,7 +1000,7 @@ bool ClauseProcessor::processMap( const parser::CharBlock &source) { using Map = omp::clause::Map; mlir::Location clauseLocation = converter.genLocation(source); - const auto &mapType = std::get>(clause.t); + const auto &[mapType, typeMods, mappers, iterator, objects] = clause.t; llvm::omp::OpenMPOffloadMappingFlags mapTypeBits = llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_NONE; // If the map type is specified, then process it else Tofrom is the @@ -1029,13 +1029,11 @@ bool ClauseProcessor::processMap( mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_DELETE; } - auto &modTypeMods = - std::get>(clause.t); - if (modTypeMods) { - if (llvm::is_contained(*modTypeMods, Map::MapTypeModifier::Always)) + if (typeMods) { + if (llvm::is_contained(*typeMods, Map::MapTypeModifier::Always)) mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_ALWAYS; // Diagnose unimplemented map-type-modifiers. - if (llvm::any_of(*modTypeMods, [](Map::MapTypeModifier m) { + if (llvm::any_of(*typeMods, [](Map::MapTypeModifier m) { return m != Map::MapTypeModifier::Always; })) { TODO(currentLocation, "Map type modifiers (other than 'ALWAYS')" @@ -1043,10 +1041,14 @@ bool ClauseProcessor::processMap( } } - if (std::get>(clause.t)) { + if (iterator) { TODO(currentLocation, "Support for iterator modifiers is not implemented yet"); } + if (mappers) { + TODO(currentLocation, + "Support for mapper modifiers is not implemented yet"); + } processMapObjects(stmtCtx, clauseLocation, std::get(clause.t), mapTypeBits, diff --git a/flang/lib/Lower/OpenMP/Clauses.cpp b/flang/lib/Lower/OpenMP/Clauses.cpp index 8639d08827f4e..bf20f42bdecaf 100644 --- a/flang/lib/Lower/OpenMP/Clauses.cpp +++ b/flang/lib/Lower/OpenMP/Clauses.cpp @@ -584,7 +584,7 @@ Defaultmap make(const parser::OmpClause::Defaultmap &inp, // clang-format on ); - auto &mods{semantics::OmpGetModifiers(inp.v)}; + auto &mods = semantics::OmpGetModifiers(inp.v); auto &t0 = std::get(inp.v.t); auto *t1 = semantics::OmpGetUniqueModifier(mods); @@ -764,37 +764,35 @@ Firstprivate make(const parser::OmpClause::Firstprivate &inp, From make(const parser::OmpClause::From &inp, semantics::SemanticsContext &semaCtx) { // inp.v -> parser::OmpFromClause - using wrapped = parser::OmpFromClause; - CLAUSET_ENUM_CONVERT( // - convert, parser::OmpFromClause::Expectation, From::Expectation, + convert, parser::OmpExpectation::Value, From::Expectation, // clang-format off MS(Present, Present) // clang-format on ); - auto &t0 = std::get>>(inp.v.t); - auto &t1 = std::get>>(inp.v.t); - auto &t2 = std::get(inp.v.t); - - assert((!t0 || t0->size() == 1) && "Only one expectation modifier allowed"); - assert((!t1 || t1->size() == 1) && "Only one iterator modifier allowed"); + auto &mods = semantics::OmpGetModifiers(inp.v); + auto *t0 = semantics::OmpGetUniqueModifier(mods); + auto *t1 = semantics::OmpGetUniqueModifier(mods); + auto *t2 = semantics::OmpGetUniqueModifier(mods); + auto &t3 = std::get(inp.v.t); - auto expectation = [&]() -> std::optional { - if (t0) - return convert(t0->front()); + auto mappers = [&]() -> std::optional> { + if (t1) + return List{Mapper{makeObject(t1->v, semaCtx)}}; return std::nullopt; }(); auto iterator = [&]() -> std::optional { - if (t1) - return makeIterator(t1->front(), semaCtx); + if (t2) + return makeIterator(*t2, semaCtx); return std::nullopt; }(); - return From{{/*Expectation=*/std::move(expectation), /*Mapper=*/std::nullopt, + return From{{/*Expectation=*/maybeApplyToV(convert, t0), + /*Mappers=*/std::move(mappers), /*Iterator=*/std::move(iterator), - /*LocatorList=*/makeObjects(t2, semaCtx)}}; + /*LocatorList=*/makeObjects(t3, semaCtx)}}; } // Full: empty @@ -963,10 +961,8 @@ Link make(const parser::OmpClause::Link &inp, Map make(const parser::OmpClause::Map &inp, semantics::SemanticsContext &semaCtx) { // inp.v -> parser::OmpMapClause - using wrapped = parser::OmpMapClause; - CLAUSET_ENUM_CONVERT( // - convert1, parser::OmpMapClause::Type, Map::MapType, + convert1, parser::OmpMapType::Value, Map::MapType, // clang-format off MS(Alloc, Alloc) MS(Delete, Delete) @@ -978,7 +974,7 @@ Map make(const parser::OmpClause::Map &inp, ); CLAUSET_ENUM_CONVERT( // - convert2, parser::OmpMapClause::TypeModifier, Map::MapTypeModifier, + convert2, parser::OmpMapTypeModifier::Value, Map::MapTypeModifier, // clang-format off MS(Always, Always) MS(Close, Close) @@ -987,42 +983,43 @@ Map make(const parser::OmpClause::Map &inp, // clang-format on ); - auto &t0 = std::get>>(inp.v.t); - auto &t1 = std::get>>(inp.v.t); - auto &t2 = std::get>>(inp.v.t); - auto &t3 = std::get(inp.v.t); - auto &t4 = std::get(inp.v.t); - - if (t4.v) - TODO_NOLOC("OmpMapClause(MAPPER(...)): user defined mapper not supported"); + auto &mods = semantics::OmpGetModifiers(inp.v); + auto *t1 = semantics::OmpGetUniqueModifier(mods); + auto *t2 = semantics::OmpGetUniqueModifier(mods); + auto *t3 = semantics::OmpGetUniqueModifier(mods); + auto &t4 = std::get(inp.v.t); - // These should have been diagnosed already. - assert((!t1 || t1->size() == 1) && "Only one iterator modifier is allowed"); - assert((!t2 || t2->size() == 1) && "Only one map type is allowed"); + auto mappers = [&]() -> std::optional> { + if (t1) + return List{Mapper{makeObject(t1->v, semaCtx)}}; + return std::nullopt; + }(); auto iterator = [&]() -> std::optional { - if (t1) - return makeIterator(t1->front(), semaCtx); + if (t2) + return makeIterator(*t2, semaCtx); return std::nullopt; }(); - std::optional maybeType; - if (t2) - maybeType = maybeApply(convert1, std::optional(t2->front())); + auto type = [&]() -> std::optional { + if (t3) + return convert1(t3->v); + return Map::MapType::Tofrom; + }(); - std::optional maybeTypeMods = maybeApply( - [&](const std::list &typeMods) { - Map::MapTypeModifiers mods; - for (wrapped::TypeModifier mod : typeMods) - mods.push_back(convert2(mod)); - return mods; - }, - t0); + Map::MapTypeModifiers typeMods; + for (auto *typeMod : + semantics::OmpGetRepeatableModifier(mods)) { + typeMods.push_back(convert2(typeMod->v)); + } + std::optional maybeTypeMods{}; + if (!typeMods.empty()) + maybeTypeMods = std::move(typeMods); - return Map{{/*MapType=*/maybeType, - /*MapTypeModifiers=*/maybeTypeMods, - /*Mapper=*/std::nullopt, /*Iterator=*/std::move(iterator), - /*LocatorList=*/makeObjects(t3, semaCtx)}}; + return Map{{/*MapType=*/std::move(type), + /*MapTypeModifiers=*/std::move(maybeTypeMods), + /*Mapper=*/std::move(mappers), /*Iterator=*/std::move(iterator), + /*LocatorList=*/makeObjects(t4, semaCtx)}}; } // Match: incomplete @@ -1316,37 +1313,35 @@ ThreadLimit make(const parser::OmpClause::ThreadLimit &inp, To make(const parser::OmpClause::To &inp, semantics::SemanticsContext &semaCtx) { // inp.v -> parser::OmpToClause - using wrapped = parser::OmpToClause; - CLAUSET_ENUM_CONVERT( // - convert, parser::OmpToClause::Expectation, To::Expectation, + convert, parser::OmpExpectation::Value, To::Expectation, // clang-format off MS(Present, Present) // clang-format on ); - auto &t0 = std::get>>(inp.v.t); - auto &t1 = std::get>>(inp.v.t); - auto &t2 = std::get(inp.v.t); - - assert((!t0 || t0->size() == 1) && "Only one expectation modifier allowed"); - assert((!t1 || t1->size() == 1) && "Only one iterator modifier allowed"); + auto &mods = semantics::OmpGetModifiers(inp.v); + auto *t0 = semantics::OmpGetUniqueModifier(mods); + auto *t1 = semantics::OmpGetUniqueModifier(mods); + auto *t2 = semantics::OmpGetUniqueModifier(mods); + auto &t3 = std::get(inp.v.t); - auto expectation = [&]() -> std::optional { - if (t0) - return convert(t0->front()); + auto mappers = [&]() -> std::optional> { + if (t1) + return List{Mapper{makeObject(t1->v, semaCtx)}}; return std::nullopt; }(); auto iterator = [&]() -> std::optional { - if (t1) - return makeIterator(t1->front(), semaCtx); + if (t2) + return makeIterator(*t2, semaCtx); return std::nullopt; }(); - return To{{/*Expectation=*/std::move(expectation), /*Mapper=*/std::nullopt, + return To{{/*Expectation=*/maybeApplyToV(convert, t0), + /*Mappers=*/{std::move(mappers)}, /*Iterator=*/std::move(iterator), - /*LocatorList=*/makeObjects(t2, semaCtx)}}; + /*LocatorList=*/makeObjects(t3, semaCtx)}}; } // UnifiedAddress: empty diff --git a/flang/lib/Lower/OpenMP/Clauses.h b/flang/lib/Lower/OpenMP/Clauses.h index 9c74404801bbc..5fac5c2271c3b 100644 --- a/flang/lib/Lower/OpenMP/Clauses.h +++ b/flang/lib/Lower/OpenMP/Clauses.h @@ -168,6 +168,7 @@ std::optional getBaseObject(const Object &object, namespace clause { using Range = tomp::type::RangeT; +using Mapper = tomp::type::MapperT; using Iterator = tomp::type::IteratorT; using IteratorSpecifier = tomp::type::IteratorSpecifierT; using DefinedOperator = tomp::type::DefinedOperatorT; diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp index ceae20270d13d..2040a3e7ed5ae 100644 --- a/flang/lib/Parser/openmp-parsers.cpp +++ b/flang/lib/Parser/openmp-parsers.cpp @@ -23,137 +23,36 @@ namespace Fortran::parser { constexpr auto startOmpLine = skipStuffBeforeStatement >> "!$OMP "_sptok; constexpr auto endOmpLine = space >> endOfLine; -// Helper class to deal with a list of modifiers of various types. -// The list (to be parsed) is assumed to start with all modifiers of the -// first type, followed by a list of modifiers of the second type, etc. -// Each list can be empty, e.g. -// mod_of_kind_2, mod_of_kind_3, mod_of_kind_5, ... -// The result type is a tuple of optional lists of each modifier type. -template -struct ConcatSeparated { - template - using OptListOf = std::optional>; - template using TupleFor = std::tuple>; - - using resultType = std::tuple, OptListOf...>; - - constexpr ConcatSeparated(ConcatSeparated &&) = default; - constexpr ConcatSeparated(const ConcatSeparated &) = default; - constexpr ConcatSeparated(Separator sep, Parser p, Parsers... ps) - : parser_(p), sepAndParsers_(sep, ps...) {} +template struct ModifierList { + constexpr ModifierList(Separator sep) : sep_(sep) {} + constexpr ModifierList(const ModifierList &) = default; + constexpr ModifierList(ModifierList &&) = default; - std::optional Parse(ParseState &state) const { - // firstParser is a list parser, it returns optional. - auto firstParser = - attempt(nonemptySeparated(parser_, std::get<0>(sepAndParsers_))); - - if constexpr (sizeof...(Parsers) == 0) { - return TupleFor{std::move(firstParser.Parse(state))}; - } else { - using restParserType = ConcatSeparated; - auto restParser = std::make_from_tuple(sepAndParsers_); - - if (auto first{firstParser.Parse(state)}) { - if (attempt(std::get<0>(sepAndParsers_)).Parse(state)) { - return std::tuple_cat(TupleFor(std::move(*first)), - std::move(*restParser.Parse(state))); - } - return std::tuple_cat(TupleFor{std::move(*first)}, - std::tuple...>{}); - } - return std::tuple_cat( - TupleFor{}, std::move(*restParser.Parse(state))); - } - } - -private: - const Parser parser_; - const std::tuple sepAndParsers_; -}; - -// Map modifiers come from four categories: -// - map-type-modifier, -// - mapper (not parsed yet), -// - iterator, -// - map-type. -// There can be zero or more map-type-modifiers, and zero or one modifier -// of every other kind. -// Syntax-wise they look like a single list, where the last element could -// be a map-type, and all elements in that list are comma-separated[1]. -// Only if there was at least one modifier (of any kind) specified, the -// list must end with ":". -// There are complications coming from the fact that the comma separating the -// two kinds of modifiers is only allowed if there is at least one modifier of -// each kind. The MapModifiers parser utilizes the ConcatSeparated parser, which -// takes care of that. ConcatSeparated returns a tuple with optional lists of -// modifiers for every type. -// [1] Any of the commas are optional, but that syntax has been deprecated -// in OpenMP 5.2, and the parsing code keeps a record of whether the commas -// were present. -template struct MapModifiers { - constexpr MapModifiers(Separator sep) : sep_(sep) {} - constexpr MapModifiers(const MapModifiers &) = default; - constexpr MapModifiers(MapModifiers &&) = default; - - // Parsing of mappers is not supported yet. - using TypeModParser = Parser; - using IterParser = Parser; - using TypeParser = Parser; - using ModParser = - ConcatSeparated; - - using resultType = typename ModParser::resultType; + using resultType = std::list; std::optional Parse(ParseState &state) const { - auto mp = ModParser(sep_, TypeModParser{}, IterParser{}, TypeParser{}); - 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)) { + auto listp{nonemptySeparated(Parser{}, sep_)}; + if (auto result{attempt(listp).Parse(state)}) { if (!attempt(":"_tok).Parse(state)) { return std::nullopt; } + return std::move(result); } - return std::move(mods); + return resultType{}; } private: 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 struct MotionModifiers { - constexpr MotionModifiers(Separator sep) : sep_(sep) {} - constexpr MotionModifiers(const MotionModifiers &) = default; - constexpr MotionModifiers(MotionModifiers &&) = default; - - using ExpParser = Parser; - using IterParser = Parser; - using ModParser = ConcatSeparated; - - using resultType = typename ModParser::resultType; - - std::optional 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_; -}; +// Use a function to create ModifierList because functions allow "partial" +// template argument deduction: "modifierList(sep)" would be legal, +// while "ModifierList(sep)" would complain about a missing template +// argument "Separator". +template +constexpr ModifierList modifierList(Separator sep) { + return ModifierList(sep); +} // OpenMP Clauses @@ -192,6 +91,16 @@ static TypeDeclarationStmt makeIterSpecDecl(std::list &&names) { // --- Parsers for clause modifiers ----------------------------------- +TYPE_PARSER(construct( // + "SIMD" >> pure(OmpChunkModifier::Value::Simd))) + +TYPE_PARSER(construct( + "SINK" >> pure(OmpDependenceType::Value::Sink) || + "SOURCE" >> pure(OmpDependenceType::Value::Source))) + +TYPE_PARSER(construct( // + "PRESENT" >> pure(OmpExpectation::Value::Present))) + TYPE_PARSER(construct( // Using Parser or Parser has the problem // that they will attempt to treat what follows the '=' as initialization. @@ -208,12 +117,9 @@ TYPE_PARSER(construct( makeIterSpecDecl, nonemptyList(Parser{}) / "="_tok)), subscriptTriplet)) -TYPE_PARSER(construct( - "SINK" >> pure(OmpDependenceType::Value::Sink) || - "SOURCE" >> pure(OmpDependenceType::Value::Source))) - // [5.0] 2.1.6 iterator -> iterator-specifier-list -TYPE_PARSER(construct("ITERATOR" >> +TYPE_PARSER(construct( // + "ITERATOR" >> parenthesized(nonemptyList(sourced(Parser{}))))) // 2.15.3.7 LINEAR (linear-list: linear-step) @@ -224,13 +130,29 @@ TYPE_PARSER(construct( // "VAL" >> pure(OmpLinearModifier::Value::Val) || "UVAL" >> pure(OmpLinearModifier::Value::Uval))) +TYPE_PARSER(construct( // + "MAPPER"_tok >> parenthesized(Parser{}))) + +// map-type -> ALLOC | DELETE | FROM | RELEASE | TO | TOFROM +TYPE_PARSER(construct( // + "ALLOC" >> pure(OmpMapType::Value::Alloc) || + "DELETE" >> pure(OmpMapType::Value::Delete) || + "FROM" >> pure(OmpMapType::Value::From) || + "RELEASE" >> pure(OmpMapType::Value::Release) || + "TO"_id >> pure(OmpMapType::Value::To) || + "TOFROM" >> pure(OmpMapType::Value::Tofrom))) + +// map-type-modifier -> ALWAYS | CLOSE | OMPX_HOLD | PRESENT +TYPE_PARSER(construct( + "ALWAYS" >> pure(OmpMapTypeModifier::Value::Always) || + "CLOSE" >> pure(OmpMapTypeModifier::Value::Close) || + "OMPX_HOLD" >> pure(OmpMapTypeModifier::Value::Ompx_Hold) || + "PRESENT" >> pure(OmpMapTypeModifier::Value::Present))) + // 2.15.3.6 REDUCTION (reduction-identifier: variable-name-list) TYPE_PARSER(construct(Parser{}) || construct(Parser{})) -TYPE_PARSER(construct( // - "SIMD" >> pure(OmpChunkModifier::Value::Simd))) - TYPE_PARSER(construct( "REPRODUCIBLE" >> pure(OmpOrderModifier::Value::Reproducible) || "UNCONSTRAINED" >> pure(OmpOrderModifier::Value::Unconstrained))) @@ -261,6 +183,17 @@ TYPE_PARSER(construct( "SCALAR" >> pure(OmpVariableCategory::Value::Scalar))) // This could be auto-generated. +TYPE_PARSER(sourced(construct( + sourced(construct(Parser{}) || + construct(Parser{}) || + construct(Parser{}))))) + +TYPE_PARSER(sourced(construct( + sourced(construct(Parser{}) || + construct(Parser{}) || + construct(Parser{}) || + construct(Parser{}))))) + TYPE_PARSER( sourced(construct(Parser{}))) @@ -273,11 +206,33 @@ TYPE_PARSER(sourced(construct(sourced( construct(Parser{}) || construct(Parser{}))))) +TYPE_PARSER(sourced(construct( + sourced(construct(Parser{}) || + construct(Parser{}) || + construct(Parser{}))))) + TYPE_PARSER(sourced( construct(Parser{}))) // --- Parsers for clauses -------------------------------------------- +/// `MOBClause` is a clause that has a +/// std::tuple. +/// Helper function to create a typical modifiers-objects clause, where the +/// commas separating individual modifiers are optional, and the clause +/// contains a bool member to indicate whether it was fully comma-separated +/// or not. +template +static inline MOBClause makeMobClause( + std::list &&mods, OmpObjectList &&objs) { + if (!mods.empty()) { + return MOBClause{std::move(mods), std::move(objs), CommaSeparated}; + } else { + using ListTy = std::list; + return MOBClause{std::optional{}, std::move(objs), CommaSeparated}; + } +} + // [5.0] 2.10.1 affinity([aff-modifier:] locator-list) // aff-modifier: interator-modifier TYPE_PARSER(construct( @@ -290,53 +245,18 @@ TYPE_PARSER(construct( "SHARED" >> pure(OmpDefaultClause::Type::Shared) || "NONE" >> pure(OmpDefaultClause::Type::None))) -// 2.5 PROC_BIND (MASTER | CLOSE | PRIMARY | SPREAD ) +// 2.5 PROC_BIND (MASTER | CLOSE | PRIMARY | SPREAD) TYPE_PARSER(construct( "CLOSE" >> pure(OmpProcBindClause::Type::Close) || "MASTER" >> pure(OmpProcBindClause::Type::Master) || "PRIMARY" >> pure(OmpProcBindClause::Type::Primary) || "SPREAD" >> pure(OmpProcBindClause::Type::Spread))) -// 2.15.5.1 map -> -// MAP ([ [map-type-modifiers [,] ] map-type : ] variable-name-list) -// map-type-modifiers -> map-type-modifier [,] [...] -// map-type-modifier -> ALWAYS | CLOSE | OMPX_HOLD | PRESENT -// map-type -> ALLOC | DELETE | FROM | RELEASE | TO | TOFROM -TYPE_PARSER(construct( - "ALWAYS" >> pure(OmpMapClause::TypeModifier::Always) || - "CLOSE" >> pure(OmpMapClause::TypeModifier::Close) || - "OMPX_HOLD" >> pure(OmpMapClause::TypeModifier::Ompx_Hold) || - "PRESENT" >> pure(OmpMapClause::TypeModifier::Present))) - -TYPE_PARSER( - construct("ALLOC" >> pure(OmpMapClause::Type::Alloc) || - "DELETE" >> pure(OmpMapClause::Type::Delete) || - "FROM" >> pure(OmpMapClause::Type::From) || - "RELEASE" >> pure(OmpMapClause::Type::Release) || - "TO"_id >> pure(OmpMapClause::Type::To) || - "TOFROM" >> pure(OmpMapClause::Type::Tofrom))) - -template -static inline OmpMapClause makeMapClause(OmpMapperIdentifier &&mm, - std::tuple>, - std::optional>, - std::optional>> &&mods, - OmpObjectList &&objs) { - auto &&[tm, it, ty] = std::move(mods); - return OmpMapClause{std::move(mm), std::move(tm), std::move(it), - std::move(ty), std::move(objs), CommasEverywhere}; -} - -TYPE_PARSER(construct( - maybe("MAPPER"_tok >> parenthesized(name) / ","_tok))) - TYPE_PARSER(construct( - applyFunction(makeMapClause, - Parser{}, MapModifiers(","_tok), - Parser{}) || - applyFunction(makeMapClause, - Parser{}, MapModifiers(maybe(","_tok)), - Parser{}))) + applyFunction(makeMobClause, + modifierList(","_tok), Parser{}) || + applyFunction(makeMobClause, + modifierList(maybe(","_tok)), Parser{}))) // [OpenMP 5.0] // 2.19.7.2 defaultmap(implicit-behavior[:variable-category]) @@ -463,30 +383,17 @@ TYPE_CONTEXT_PARSER("Omp Depend clause"_en_US, TYPE_CONTEXT_PARSER("Omp Doacross clause"_en_US, construct(Parser{})) -TYPE_PARSER(construct( - "PRESENT" >> pure(OmpFromClause::Expectation::Present))) - -template -static inline MotionClause makeMotionClause( - std::tuple>, - std::optional>> &&mods, - OmpObjectList &&objs) { - auto &&[exp, iter] = std::move(mods); - return MotionClause( - std::move(exp), std::move(iter), std::move(objs), CommasEverywhere); -} - TYPE_PARSER(construct( - applyFunction(makeMotionClause, - MotionModifiers(","_tok), Parser{}) || - applyFunction(makeMotionClause, - MotionModifiers(maybe(","_tok)), Parser{}))) + applyFunction(makeMobClause, + modifierList(","_tok), Parser{}) || + applyFunction(makeMobClause, + modifierList(maybe(","_tok)), Parser{}))) TYPE_PARSER(construct( - applyFunction(makeMotionClause, - MotionModifiers(","_tok), Parser{}) || - applyFunction(makeMotionClause, - MotionModifiers(maybe(","_tok)), Parser{}))) + applyFunction(makeMobClause, + modifierList(","_tok), Parser{}) || + applyFunction(makeMobClause, + modifierList(maybe(","_tok)), Parser{}))) TYPE_CONTEXT_PARSER("Omp LINEAR clause"_en_US, construct( diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp index 4881da848c347..fe3f6ce7aa629 100644 --- a/flang/lib/Parser/unparse.cpp +++ b/flang/lib/Parser/unparse.cpp @@ -2084,6 +2084,11 @@ class UnparseVisitor { Walk(x.v); Put(")"); } + void Unparse(const OmpMapper &x) { + Word("MAPPER("); + Walk(x.v); + Put(")"); + } void Unparse(const OmpLastprivateClause &x) { Walk( std::get>(x.t), @@ -2091,46 +2096,8 @@ class UnparseVisitor { Walk(std::get(x.t)); } void Unparse(const OmpMapClause &x) { - auto &typeMod = - std::get>>(x.t); - auto &iter = std::get>>(x.t); - auto &type = std::get>>(x.t); - auto &mapper = std::get(x.t); - - // For a given list of items, if the item has a value, then walk it. - // Print commas between items that have values. - // Return 'true' if something did get printed, otherwise 'false'. - bool needComma{false}; - if (mapper.v) { - Word("MAPPER("); - Walk(*mapper.v); - Put(")"); - needComma = true; - } - if (typeMod) { - if (needComma) { - Put(", "); - } - Walk(*typeMod); - needComma = true; - } - if (iter) { - if (needComma) { - Put(", "); - } - Walk(*iter); - needComma = true; - } - if (type) { - if (needComma) { - Put(", "); - } - Walk(*type); - needComma = true; - } - if (needComma) { - Put(": "); - } + using Modifier = OmpMapClause::Modifier; + Walk(std::get>>(x.t), ": "); Walk(std::get(x.t)); } void Unparse(const OmpScheduleClause &x) { @@ -2153,24 +2120,8 @@ class UnparseVisitor { Walk(std::get>(x.t)); } void Unparse(const OmpFromClause &x) { - auto &expect{ - std::get>>(x.t)}; - auto &iter{std::get>>(x.t)}; - bool needComma{false}; - if (expect) { - Walk(*expect); - needComma = true; - } - if (iter) { - if (needComma) { - Put(", "); - } - Walk(*iter); - needComma = true; - } - if (needComma) { - Put(": "); - } + using Modifier = OmpFromClause::Modifier; + Walk(std::get>>(x.t), ": "); Walk(std::get(x.t)); } void Unparse(const OmpIfClause &x) { @@ -2257,24 +2208,8 @@ class UnparseVisitor { Walk(":", std::get>>(x.t)); } void Unparse(const OmpToClause &x) { - auto &expect{ - std::get>>(x.t)}; - auto &iter{std::get>>(x.t)}; - bool needComma{false}; - if (expect) { - Walk(*expect); - needComma = true; - } - if (iter) { - if (needComma) { - Put(", "); - } - Walk(*iter); - needComma = true; - } - if (needComma) { - Put(": "); - } + using Modifier = OmpToClause::Modifier; + Walk(std::get>>(x.t), ": "); Walk(std::get(x.t)); } #define GEN_FLANG_CLAUSE_UNPARSE @@ -2913,7 +2848,7 @@ class UnparseVisitor { WALK_NESTED_ENUM(OmpDeviceClause, DeviceModifier) // OMP device modifier WALK_NESTED_ENUM(OmpDeviceTypeClause, Type) // OMP DEVICE_TYPE WALK_NESTED_ENUM(OmpReductionModifier, Value) // OMP reduction-modifier - WALK_NESTED_ENUM(OmpFromClause, Expectation) // OMP motion-expectation + WALK_NESTED_ENUM(OmpExpectation, Value) // OMP motion-expectation WALK_NESTED_ENUM(OmpIfClause, DirectiveNameModifier) // OMP directive-modifier WALK_NESTED_ENUM(OmpCancelType, Type) // OMP cancel-type WALK_NESTED_ENUM(OmpOrderClause, Ordering) // OMP ordering @@ -2921,8 +2856,8 @@ class UnparseVisitor { WALK_NESTED_ENUM( OmpGrainsizeClause, Prescriptiveness) // OMP grainsize-modifier WALK_NESTED_ENUM(OmpNumTasksClause, Prescriptiveness) // OMP numtasks-modifier - WALK_NESTED_ENUM(OmpMapClause, Type) // OMP map-type - WALK_NESTED_ENUM(OmpMapClause, TypeModifier) // OMP map-type-modifier + WALK_NESTED_ENUM(OmpMapType, Value) // OMP map-type + WALK_NESTED_ENUM(OmpMapTypeModifier, Value) // OMP map-type-modifier #undef WALK_NESTED_ENUM void Unparse(const ReductionOperator::Operator x) { switch (x) { diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp index 6ef4e851f03ab..3733ebfaf9492 100644 --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -2860,7 +2860,8 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Destroy &x) { void OmpStructureChecker::Enter(const parser::OmpClause::Reduction &x) { CheckAllowedClause(llvm::omp::Clause::OMPC_reduction); - if (OmpVerifyModifiers(x.v, GetContext().clauseSource, context_)) { + if (OmpVerifyModifiers(x.v, llvm::omp::OMPC_reduction, + GetContext().clauseSource, context_)) { if (CheckReductionOperators(x)) { CheckReductionTypeList(x); } @@ -3401,7 +3402,8 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Defaultmap &x) { ThisVersion(version), TryVersion(50)); } } - if (!OmpVerifyModifiers(x.v, GetContext().clauseSource, context_)) { + if (!OmpVerifyModifiers(x.v, llvm::omp::OMPC_defaultmap, + GetContext().clauseSource, context_)) { // If modifier verification fails, return early. return; } @@ -3479,15 +3481,15 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Linear &x) { } void OmpStructureChecker::CheckAllowedMapTypes( - const parser::OmpMapClause::Type &type, - const std::list &allowedMapTypeList) { + const parser::OmpMapType::Value &type, + const std::list &allowedMapTypeList) { if (!llvm::is_contained(allowedMapTypeList, type)) { std::string commaSeparatedMapTypes; llvm::interleave( allowedMapTypeList.begin(), allowedMapTypeList.end(), - [&](const parser::OmpMapClause::Type &mapType) { + [&](const parser::OmpMapType::Value &mapType) { commaSeparatedMapTypes.append(parser::ToUpperCaseLetters( - parser::OmpMapClause::EnumToString(mapType))); + parser::OmpMapType::EnumToString(mapType))); }, [&] { commaSeparatedMapTypes.append(", "); }); context_.Say(GetContext().clauseSource, @@ -3499,40 +3501,23 @@ void OmpStructureChecker::CheckAllowedMapTypes( void OmpStructureChecker::Enter(const parser::OmpClause::Map &x) { CheckAllowedClause(llvm::omp::Clause::OMPC_map); - using TypeMod = parser::OmpMapClause::TypeModifier; - using Type = parser::OmpMapClause::Type; - using IterMod = parser::OmpIterator; + if (!OmpVerifyModifiers( + x.v, llvm::omp::OMPC_map, GetContext().clauseSource, context_)) { + return; + } + auto &modifiers{OmpGetModifiers(x.v)}; unsigned version{context_.langOptions().OpenMPVersion}; if (auto commas{std::get(x.v.t)}; !commas && version >= 52) { context_.Say(GetContext().clauseSource, "The specification of modifiers without comma separators for the " "'MAP' clause has been deprecated in OpenMP 5.2"_port_en_US); } - if (auto &mapTypeMod{std::get>>(x.v.t)}) { - if (auto *dup{FindDuplicateEntry(*mapTypeMod)}) { - context_.Say(GetContext().clauseSource, - "Duplicate map-type-modifier entry '%s' will be ignored"_warn_en_US, - parser::ToUpperCaseLetters(parser::OmpMapClause::EnumToString(*dup))); - } - } - // The size of any of the optional lists is never 0, instead of the list - // being empty, it will be a nullopt. - if (auto &iterMod{std::get>>(x.v.t)}) { - if (iterMod->size() != 1) { - context_.Say(GetContext().clauseSource, - "Only one iterator-modifier is allowed"_err_en_US); - } - CheckIteratorModifier(iterMod->front()); + if (auto *iter{OmpGetUniqueModifier(modifiers)}) { + CheckIteratorModifier(*iter); } - if (auto &mapType{std::get>>(x.v.t)}) { - if (mapType->size() != 1) { - context_.Say(GetContext().clauseSource, - "Multiple map types are not allowed"_err_en_US); - return; - } - parser::OmpMapClause::Type type{mapType->front()}; - + if (auto *type{OmpGetUniqueModifier(modifiers)}) { + using Value = parser::OmpMapType::Value; switch (GetContext().directive) { case llvm::omp::Directive::OMPD_target: case llvm::omp::Directive::OMPD_target_teams: @@ -3542,25 +3527,43 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Map &x) { case llvm::omp::Directive::OMPD_target_teams_distribute_parallel_do_simd: case llvm::omp::Directive::OMPD_target_data: CheckAllowedMapTypes( - type, {Type::To, Type::From, Type::Tofrom, Type::Alloc}); + type->v, {Value::To, Value::From, Value::Tofrom, Value::Alloc}); break; case llvm::omp::Directive::OMPD_target_enter_data: - CheckAllowedMapTypes(type, {Type::To, Type::Alloc}); + CheckAllowedMapTypes(type->v, {Value::To, Value::Alloc}); break; case llvm::omp::Directive::OMPD_target_exit_data: - CheckAllowedMapTypes(type, {Type::From, Type::Release, Type::Delete}); + CheckAllowedMapTypes( + type->v, {Value::From, Value::Release, Value::Delete}); break; default: break; } } + + auto &&typeMods{ + OmpGetRepeatableModifier(modifiers)}; + struct Less { + using Iterator = decltype(typeMods.begin()); + bool operator()(Iterator a, Iterator b) const { + const parser::OmpMapTypeModifier *pa = *a; + const parser::OmpMapTypeModifier *pb = *b; + return pa->v < pb->v; + } + }; + if (auto maybeIter{FindDuplicate(typeMods)}) { + context_.Say(GetContext().clauseSource, + "Duplicate map-type-modifier entry '%s' will be ignored"_warn_en_US, + parser::ToUpperCaseLetters( + parser::OmpMapTypeModifier::EnumToString((**maybeIter)->v))); + } } void OmpStructureChecker::Enter(const parser::OmpClause::Schedule &x) { CheckAllowedClause(llvm::omp::Clause::OMPC_schedule); const parser::OmpScheduleClause &scheduleClause = x.v; - if (!OmpVerifyModifiers( - scheduleClause, GetContext().clauseSource, context_)) { + if (!OmpVerifyModifiers(scheduleClause, llvm::omp::OMPC_schedule, + GetContext().clauseSource, context_)) { return; } @@ -3730,8 +3733,8 @@ void OmpStructureChecker::CheckDoacross(const parser::OmpDoacross &doa) { // Check if the variables in the iteration vector are unique. struct Less { - bool operator()( - const parser::OmpIteration *a, const parser::OmpIteration *b) const { + using Iterator = std::list::const_iterator; + bool operator()(Iterator a, Iterator b) const { auto namea{std::get(a->t)}; auto nameb{std::get(b->t)}; assert(namea.symbol && nameb.symbol && "Unresolved symbols"); @@ -3741,8 +3744,8 @@ void OmpStructureChecker::CheckDoacross(const parser::OmpDoacross &doa) { reinterpret_cast(nameb.symbol); } }; - if (auto *duplicate{FindDuplicateEntry(vec)}) { - auto name{std::get(duplicate->t)}; + if (auto maybeIter{FindDuplicate(vec)}) { + auto name{std::get((*maybeIter)->t)}; context_.Say(name.source, "Duplicate variable '%s' in the iteration vector"_err_en_US, name.ToString()); @@ -4065,35 +4068,16 @@ 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::OmpIterator; - - if (auto &expMod{std::get>>(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 (!OmpVerifyModifiers( + x.v, llvm::omp::OMPC_from, GetContext().clauseSource, context_)) { + return; } - if (auto &iterMod{std::get>>(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()); + auto &modifiers{OmpGetModifiers(x.v)}; + unsigned version{context_.langOptions().OpenMPVersion}; + + if (auto *iter{OmpGetUniqueModifier(modifiers)}) { + CheckIteratorModifier(*iter); } const auto &objList{std::get(x.v.t)}; @@ -4117,6 +4101,12 @@ void OmpStructureChecker::Enter(const parser::OmpClause::From &x) { void OmpStructureChecker::Enter(const parser::OmpClause::To &x) { CheckAllowedClause(llvm::omp::Clause::OMPC_to); + if (!OmpVerifyModifiers( + x.v, llvm::omp::OMPC_to, GetContext().clauseSource, context_)) { + return; + } + + auto &modifiers{OmpGetModifiers(x.v)}; unsigned version{context_.langOptions().OpenMPVersion}; // The "to" clause is only allowed on "declare target" (pre-5.1), and @@ -4129,35 +4119,10 @@ void OmpStructureChecker::Enter(const parser::OmpClause::To &x) { if (GetContext().directive == llvm::omp::OMPD_declare_target) { return; } - assert(GetContext().directive == llvm::omp::OMPD_target_update); - using ExpMod = parser::OmpFromClause::Expectation; - using IterMod = parser::OmpIterator; - if (auto &expMod{std::get>>(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>>(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()); + assert(GetContext().directive == llvm::omp::OMPD_target_update); + if (auto *iter{OmpGetUniqueModifier(modifiers)}) { + CheckIteratorModifier(*iter); } const auto &objList{std::get(x.v.t)}; diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h index cd0a475937613..4ce52bebd5a73 100644 --- a/flang/lib/Semantics/check-omp-structure.h +++ b/flang/lib/Semantics/check-omp-structure.h @@ -161,16 +161,15 @@ class OmpStructureChecker void HasInvalidDistributeNesting(const parser::OpenMPLoopConstruct &x); void HasInvalidLoopBinding(const parser::OpenMPLoopConstruct &x); // specific clause related - void CheckAllowedMapTypes(const parser::OmpMapClause::Type &, - const std::list &); + void CheckAllowedMapTypes(const parser::OmpMapType::Value &, + const std::list &); llvm::StringRef getClauseName(llvm::omp::Clause clause) override; llvm::StringRef getDirectiveName(llvm::omp::Directive directive) override; - template struct DefaultLess { - bool operator()(const T *a, const T *b) const { return *a < *b; } - }; - template > - const T *FindDuplicateEntry(const std::list &); + template < // + typename LessTy, typename RangeTy, + typename IterTy = decltype(std::declval().begin())> + std::optional FindDuplicate(RangeTy &&); void CheckDependList(const parser::DataRef &); void CheckDependArraySection( @@ -274,22 +273,20 @@ class OmpStructureChecker std::vector loopStack_; }; -template -const T *OmpStructureChecker::FindDuplicateEntry(const std::list &list) { - // Add elements of the list to a set. If the insertion fails, return - // the address of the failing element. - - // The objects of type T may not be copyable, so add their addresses - // to the set. The set will need to compare the actual objects, so - // the custom comparator is provided. - std::set uniq; - - for (const T &item : list) { - if (!uniq.insert(&item).second) { - return &item; +/// Find a duplicate entry in the range, and return an iterator to it. +/// If there are no duplicate entries, return nullopt. +template +std::optional OmpStructureChecker::FindDuplicate(RangeTy &&range) { + // Deal with iterators, since the actual elements may be rvalues (i.e. + // have no addresses), for example with custom-constructed ranges that + // are not simple c.begin()..c.end(). + std::set uniq; + for (auto it{range.begin()}, end{range.end()}; it != end; ++it) { + if (!uniq.insert(it).second) { + return it; } } - return nullptr; + return std::nullopt; } } // namespace Fortran::semantics diff --git a/flang/lib/Semantics/openmp-modifiers.cpp b/flang/lib/Semantics/openmp-modifiers.cpp index e0d73e605c73b..1fd2358aa594e 100644 --- a/flang/lib/Semantics/openmp-modifiers.cpp +++ b/flang/lib/Semantics/openmp-modifiers.cpp @@ -40,7 +40,13 @@ static unsigned findVersion( } } - assert(found != 0 && "cannot locate entry for version in map"); + // It can happen that the above search will not find any version, for + // example when the minimum version in the map is higher than the current + // version. This is really an error, but this situation should be handled + // gracefully, so make some sensible choice and return it. + if (found == 0) { + found = !map.empty() ? map.begin()->first : versions.front(); + } return found; } @@ -52,6 +58,19 @@ const OmpClauses &OmpModifierDescriptor::clauses(unsigned version) const { return clauses_.at(findVersion(version, clauses_)); } +unsigned OmpModifierDescriptor::since(llvm::omp::Clause id) const { + unsigned found{[&]() { + for (auto &[v, cs] : clauses_) { + if (cs.test(id)) { + return v; + } + } + return ~0u; + }()}; + + return found <= 45 ? 0 : found; +} + // Note: The intent for these functions is to have them be automatically- // generated in the future. @@ -89,6 +108,22 @@ const OmpModifierDescriptor &OmpGetDescriptor() { return desc; } +template <> +const OmpModifierDescriptor &OmpGetDescriptor() { + static const OmpModifierDescriptor desc{ + /*name=*/"expectation", + /*props=*/ + { + {51, {OmpProperty::Unique}}, + }, + /*clauses=*/ + { + {51, {Clause::OMPC_from, Clause::OMPC_to}}, + }, + }; + return desc; +} + template <> const OmpModifierDescriptor &OmpGetDescriptor() { static const OmpModifierDescriptor desc{ @@ -124,6 +159,54 @@ const OmpModifierDescriptor &OmpGetDescriptor() { return desc; } +template <> // +const OmpModifierDescriptor &OmpGetDescriptor() { + static const OmpModifierDescriptor desc{ + /*name=*/"mapper", + /*props=*/ + { + {50, {OmpProperty::Unique}}, + }, + /*clauses=*/ + { + {50, {Clause::OMPC_from, Clause::OMPC_map, Clause::OMPC_to}}, + }, + }; + return desc; +} + +template <> +const OmpModifierDescriptor &OmpGetDescriptor() { + static const OmpModifierDescriptor desc{ + /*name=*/"map-type", + /*props=*/ + { + {45, {OmpProperty::Ultimate}}, + }, + /*clauses=*/ + { + {45, {Clause::OMPC_map}}, + }, + }; + return desc; +} + +template <> +const OmpModifierDescriptor &OmpGetDescriptor() { + static const OmpModifierDescriptor desc{ + /*name=*/"map-type-modifier", + /*props=*/ + { + {45, {}}, // Repeatable + }, + /*clauses=*/ + { + {45, {Clause::OMPC_map}}, + }, + }; + return desc; +} + template <> const OmpModifierDescriptor &OmpGetDescriptor() { static const OmpModifierDescriptor desc{ diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp index 107bd3b09019a..0c3708b3fd29b 100644 --- a/flang/lib/Semantics/resolve-directives.cpp +++ b/flang/lib/Semantics/resolve-directives.cpp @@ -641,28 +641,25 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor { void Post(const parser::OmpMapClause &x) { Symbol::Flag ompFlag = Symbol::Flag::OmpMapToFrom; - // There is only one `type' allowed, but it's parsed as a list. Multiple - // types are diagnosed in the semantic checks for OpenMP. - if (const auto &mapType{ - std::get>>( - x.t)}) { - switch (mapType->front()) { - case parser::OmpMapClause::Type::To: + auto &mods{OmpGetModifiers(x)}; + if (auto *mapType{OmpGetUniqueModifier(mods)}) { + switch (mapType->v) { + case parser::OmpMapType::Value::To: ompFlag = Symbol::Flag::OmpMapTo; break; - case parser::OmpMapClause::Type::From: + case parser::OmpMapType::Value::From: ompFlag = Symbol::Flag::OmpMapFrom; break; - case parser::OmpMapClause::Type::Tofrom: + case parser::OmpMapType::Value::Tofrom: ompFlag = Symbol::Flag::OmpMapToFrom; break; - case parser::OmpMapClause::Type::Alloc: + case parser::OmpMapType::Value::Alloc: ompFlag = Symbol::Flag::OmpMapAlloc; break; - case parser::OmpMapClause::Type::Release: + case parser::OmpMapType::Value::Release: ompFlag = Symbol::Flag::OmpMapRelease; break; - case parser::OmpMapClause::Type::Delete: + case parser::OmpMapType::Value::Delete: ompFlag = Symbol::Flag::OmpMapDelete; break; } diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp index 929d35a4717dc..b576f59e8c7e5 100644 --- a/flang/lib/Semantics/resolve-names.cpp +++ b/flang/lib/Semantics/resolve-names.cpp @@ -31,6 +31,7 @@ #include "flang/Parser/tools.h" #include "flang/Semantics/attr.h" #include "flang/Semantics/expression.h" +#include "flang/Semantics/openmp-modifiers.h" #include "flang/Semantics/program-tree.h" #include "flang/Semantics/scope.h" #include "flang/Semantics/semantics.h" @@ -1642,27 +1643,27 @@ bool OmpVisitor::Pre(const parser::OpenMPDeclareMapperConstruct &x) { } bool OmpVisitor::Pre(const parser::OmpMapClause &x) { - const auto &mid{std::get(x.t)}; - if (const auto &mapperName{mid.v}) { - if (const auto symbol = FindSymbol(currScope(), *mapperName)) { + auto &mods{OmpGetModifiers(x)}; + if (auto *mapper{OmpGetUniqueModifier(mods)}) { + if (auto *symbol{FindSymbol(currScope(), mapper->v)}) { // TODO: Do we need a specific flag or type here, to distinghuish against // other ConstructName things? Leaving this for the full implementation // of mapper lowering. auto *misc{symbol->detailsIf()}; if (!misc || misc->kind() != MiscDetails::Kind::ConstructName) - context().Say(mapperName->source, - "Name '%s' should be a mapper name"_err_en_US, mapperName->source); + context().Say(mapper->v.source, + "Name '%s' should be a mapper name"_err_en_US, mapper->v.source); else - mapperName->symbol = symbol; + mapper->v.symbol = symbol; } else { - mapperName->symbol = &MakeSymbol( - *mapperName, MiscDetails{MiscDetails::Kind::ConstructName}); + mapper->v.symbol = + &MakeSymbol(mapper->v, MiscDetails{MiscDetails::Kind::ConstructName}); // TODO: When completing the implementation, we probably want to error if // the symbol is not declared, but right now, testing that the TODO for - // OmpMapclause happens is obscured by the TODO for declare mapper, so + // OmpMapClause happens is obscured by the TODO for declare mapper, so // leaving this out. Remove the above line once the declare mapper is - // implemented. context().Say(mapperName->source, "'%s' not - // declared"_err_en_US, mapperName->source); + // implemented. context().Say(mapper->v.source, "'%s' not + // declared"_err_en_US, mapper->v.source); } } return true; diff --git a/flang/test/Lower/OpenMP/Todo/map-mapper.f90 b/flang/test/Lower/OpenMP/Todo/map-mapper.f90 index d83c20db29307..9554ffd5fda7b 100644 --- a/flang/test/Lower/OpenMP/Todo/map-mapper.f90 +++ b/flang/test/Lower/OpenMP/Todo/map-mapper.f90 @@ -8,7 +8,7 @@ program p !!end type t1 !!!$omp declare mapper(xx : t1 :: nn) map(nn, nn%x) !$omp target map(mapper(xx), from:a) -!CHECK: not yet implemented: OmpMapClause(MAPPER(...)) +!CHECK: not yet implemented: Support for mapper modifiers is not implemented yet do i=1,n a(i) = 4.2 end do diff --git a/flang/test/Parser/OpenMP/from-clause.f90 b/flang/test/Parser/OpenMP/from-clause.f90 index cff9c077c0a94..acd5843ff0c4a 100644 --- a/flang/test/Parser/OpenMP/from-clause.f90 +++ b/flang/test/Parser/OpenMP/from-clause.f90 @@ -28,7 +28,7 @@ subroutine f01(x) !PARSE-TREE: OmpSimpleStandaloneDirective -> llvm::omp::Directive = target update !PARSE-TREE: OmpClauseList -> OmpClause -> From -> OmpFromClause -!PARSE-TREE: | Expectation = Present +!PARSE-TREE: | Modifier -> OmpExpectation -> Value = Present !PARSE-TREE: | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x' !PARSE-TREE: | bool = 'true' @@ -44,8 +44,8 @@ subroutine f02(x) !PARSE-TREE: OmpSimpleStandaloneDirective -> llvm::omp::Directive = target update !PARSE-TREE: OmpClauseList -> OmpClause -> From -> OmpFromClause -!PARSE-TREE: | Expectation = Present -!PARSE-TREE: | OmpIterator -> OmpIteratorSpecifier +!PARSE-TREE: | Modifier -> OmpExpectation -> Value = Present +!PARSE-TREE: | Modifier -> OmpIterator -> OmpIteratorSpecifier !PARSE-TREE: | | TypeDeclarationStmt !PARSE-TREE: | | | DeclarationTypeSpec -> IntrinsicTypeSpec -> IntegerTypeSpec -> !PARSE-TREE: | | | EntityDecl @@ -73,8 +73,8 @@ subroutine f03(x) !PARSE-TREE: OmpSimpleStandaloneDirective -> llvm::omp::Directive = target update !PARSE-TREE: OmpClauseList -> OmpClause -> From -> OmpFromClause -!PARSE-TREE: | Expectation = Present -!PARSE-TREE: | OmpIterator -> OmpIteratorSpecifier +!PARSE-TREE: | Modifier -> OmpExpectation -> Value = Present +!PARSE-TREE: | Modifier -> OmpIterator -> OmpIteratorSpecifier !PARSE-TREE: | | TypeDeclarationStmt !PARSE-TREE: | | | DeclarationTypeSpec -> IntrinsicTypeSpec -> IntegerTypeSpec -> !PARSE-TREE: | | | EntityDecl diff --git a/flang/test/Parser/OpenMP/map-modifiers.f90 b/flang/test/Parser/OpenMP/map-modifiers.f90 index 578512283c4dc..4e034e51352e4 100644 --- a/flang/test/Parser/OpenMP/map-modifiers.f90 +++ b/flang/test/Parser/OpenMP/map-modifiers.f90 @@ -18,11 +18,11 @@ subroutine f00(x) !PARSE-TREE: OmpBeginBlockDirective !PARSE-TREE: | OmpBlockDirective -> llvm::omp::Directive = target !PARSE-TREE: | OmpClauseList -> OmpClause -> Map -> OmpMapClause -!PARSE-TREE: | | TypeModifier = Ompx_Hold -!PARSE-TREE: | | TypeModifier = Always -!PARSE-TREE: | | TypeModifier = Present -!PARSE-TREE: | | TypeModifier = Close -!PARSE-TREE: | | Type = To +!PARSE-TREE: | | Modifier -> OmpMapTypeModifier -> Value = Ompx_Hold +!PARSE-TREE: | | Modifier -> OmpMapTypeModifier -> Value = Always +!PARSE-TREE: | | Modifier -> OmpMapTypeModifier -> Value = Present +!PARSE-TREE: | | Modifier -> OmpMapTypeModifier -> Value = Close +!PARSE-TREE: | | Modifier -> OmpMapType -> Value = To !PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x' !PARSE-TREE: | | bool = 'true' @@ -43,10 +43,10 @@ subroutine f01(x) !PARSE-TREE: OmpBeginBlockDirective !PARSE-TREE: | OmpBlockDirective -> llvm::omp::Directive = target !PARSE-TREE: | OmpClauseList -> OmpClause -> Map -> OmpMapClause -!PARSE-TREE: | | TypeModifier = Ompx_Hold -!PARSE-TREE: | | TypeModifier = Always -!PARSE-TREE: | | TypeModifier = Present -!PARSE-TREE: | | TypeModifier = Close +!PARSE-TREE: | | Modifier -> OmpMapTypeModifier -> Value = Ompx_Hold +!PARSE-TREE: | | Modifier -> OmpMapTypeModifier -> Value = Always +!PARSE-TREE: | | Modifier -> OmpMapTypeModifier -> Value = Present +!PARSE-TREE: | | Modifier -> OmpMapTypeModifier -> Value = Close !PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x' !PARSE-TREE: | | bool = 'true' @@ -67,7 +67,7 @@ subroutine f02(x) !PARSE-TREE: OmpBeginBlockDirective !PARSE-TREE: | OmpBlockDirective -> llvm::omp::Directive = target !PARSE-TREE: | OmpClauseList -> OmpClause -> Map -> OmpMapClause -!PARSE-TREE: | | Type = From +!PARSE-TREE: | | Modifier -> OmpMapType -> Value = From !PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x' !PARSE-TREE: | | bool = 'true' @@ -108,11 +108,11 @@ subroutine f04(x) !PARSE-TREE: OmpBeginBlockDirective !PARSE-TREE: | OmpBlockDirective -> llvm::omp::Directive = target !PARSE-TREE: | OmpClauseList -> OmpClause -> Map -> OmpMapClause -!PARSE-TREE: | | TypeModifier = Ompx_Hold -!PARSE-TREE: | | TypeModifier = Always -!PARSE-TREE: | | TypeModifier = Present -!PARSE-TREE: | | TypeModifier = Close -!PARSE-TREE: | | Type = To +!PARSE-TREE: | | Modifier -> OmpMapTypeModifier -> Value = Ompx_Hold +!PARSE-TREE: | | Modifier -> OmpMapTypeModifier -> Value = Always +!PARSE-TREE: | | Modifier -> OmpMapTypeModifier -> Value = Present +!PARSE-TREE: | | Modifier -> OmpMapTypeModifier -> Value = Close +!PARSE-TREE: | | Modifier -> OmpMapType -> Value = To !PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x' !PARSE-TREE: | | bool = 'false' @@ -133,10 +133,10 @@ subroutine f05(x) !PARSE-TREE: OmpBeginBlockDirective !PARSE-TREE: | OmpBlockDirective -> llvm::omp::Directive = target !PARSE-TREE: | OmpClauseList -> OmpClause -> Map -> OmpMapClause -!PARSE-TREE: | | TypeModifier = Ompx_Hold -!PARSE-TREE: | | TypeModifier = Always -!PARSE-TREE: | | TypeModifier = Present -!PARSE-TREE: | | TypeModifier = Close +!PARSE-TREE: | | Modifier -> OmpMapTypeModifier -> Value = Ompx_Hold +!PARSE-TREE: | | Modifier -> OmpMapTypeModifier -> Value = Always +!PARSE-TREE: | | Modifier -> OmpMapTypeModifier -> Value = Present +!PARSE-TREE: | | Modifier -> OmpMapTypeModifier -> Value = Close !PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x' !PARSE-TREE: | | bool = 'true' @@ -158,8 +158,8 @@ subroutine f10(x) !PARSE-TREE: OmpBeginBlockDirective !PARSE-TREE: | OmpBlockDirective -> llvm::omp::Directive = target !PARSE-TREE: | OmpClauseList -> OmpClause -> Map -> OmpMapClause -!PARSE-TREE: | | TypeModifier = Present -!PARSE-TREE: | | OmpIterator -> OmpIteratorSpecifier +!PARSE-TREE: | | Modifier -> OmpMapTypeModifier -> Value = Present +!PARSE-TREE: | | Modifier -> OmpIterator -> OmpIteratorSpecifier !PARSE-TREE: | | | TypeDeclarationStmt !PARSE-TREE: | | | | DeclarationTypeSpec -> IntrinsicTypeSpec -> IntegerTypeSpec -> !PARSE-TREE: | | | | EntityDecl @@ -169,7 +169,7 @@ subroutine f10(x) !PARSE-TREE: | | | | | LiteralConstant -> IntLiteralConstant = '1' !PARSE-TREE: | | | | Scalar -> Integer -> Expr = '10_4' !PARSE-TREE: | | | | | LiteralConstant -> IntLiteralConstant = '10' -!PARSE-TREE: | | Type = To +!PARSE-TREE: | | Modifier -> OmpMapType -> Value = To !PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> ArrayElement !PARSE-TREE: | | | DataRef -> Name = 'x' !PARSE-TREE: | | | SectionSubscript -> Integer -> Expr = 'i' @@ -193,8 +193,8 @@ subroutine f11(x) !PARSE-TREE: OmpBeginBlockDirective !PARSE-TREE: | OmpBlockDirective -> llvm::omp::Directive = target !PARSE-TREE: | OmpClauseList -> OmpClause -> Map -> OmpMapClause -!PARSE-TREE: | | TypeModifier = Present -!PARSE-TREE: | | OmpIterator -> OmpIteratorSpecifier +!PARSE-TREE: | | Modifier -> OmpMapTypeModifier -> Value = Present +!PARSE-TREE: | | Modifier -> OmpIterator -> OmpIteratorSpecifier !PARSE-TREE: | | | TypeDeclarationStmt !PARSE-TREE: | | | | DeclarationTypeSpec -> IntrinsicTypeSpec -> IntegerTypeSpec -> !PARSE-TREE: | | | | EntityDecl @@ -204,7 +204,7 @@ subroutine f11(x) !PARSE-TREE: | | | | | LiteralConstant -> IntLiteralConstant = '1' !PARSE-TREE: | | | | Scalar -> Integer -> Expr = '10_4' !PARSE-TREE: | | | | | LiteralConstant -> IntLiteralConstant = '10' -!PARSE-TREE: | | Type = To +!PARSE-TREE: | | Modifier -> OmpMapType -> Value = To !PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> ArrayElement !PARSE-TREE: | | | DataRef -> Name = 'x' !PARSE-TREE: | | | SectionSubscript -> Integer -> Expr = 'i' @@ -228,8 +228,8 @@ subroutine f12(x) !PARSE-TREE: OmpBeginBlockDirective !PARSE-TREE: | OmpBlockDirective -> llvm::omp::Directive = target !PARSE-TREE: | OmpClauseList -> OmpClause -> Map -> OmpMapClause -!PARSE-TREE: | | TypeModifier = Present -!PARSE-TREE: | | OmpIterator -> OmpIteratorSpecifier +!PARSE-TREE: | | Modifier -> OmpMapTypeModifier -> Value = Present +!PARSE-TREE: | | Modifier -> OmpIterator -> OmpIteratorSpecifier !PARSE-TREE: | | | TypeDeclarationStmt !PARSE-TREE: | | | | DeclarationTypeSpec -> IntrinsicTypeSpec -> IntegerTypeSpec -> !PARSE-TREE: | | | | EntityDecl @@ -239,17 +239,17 @@ subroutine f12(x) !PARSE-TREE: | | | | | LiteralConstant -> IntLiteralConstant = '1' !PARSE-TREE: | | | | Scalar -> Integer -> Expr = '10_4' !PARSE-TREE: | | | | | LiteralConstant -> IntLiteralConstant = '10' -!PARSE-TREE: | | OmpIteratorSpecifier -!PARSE-TREE: | | | TypeDeclarationStmt -!PARSE-TREE: | | | | DeclarationTypeSpec -> IntrinsicTypeSpec -> IntegerTypeSpec -> -!PARSE-TREE: | | | | EntityDecl -!PARSE-TREE: | | | | | Name = 'j' -!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: | | Type = To +!PARSE-TREE: | | | OmpIteratorSpecifier +!PARSE-TREE: | | | | TypeDeclarationStmt +!PARSE-TREE: | | | | | DeclarationTypeSpec -> IntrinsicTypeSpec -> IntegerTypeSpec -> +!PARSE-TREE: | | | | | EntityDecl +!PARSE-TREE: | | | | | | Name = 'j' +!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: | | Modifier -> OmpMapType -> Value = To !PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> ArrayElement !PARSE-TREE: | | | DataRef -> Name = 'x' !PARSE-TREE: | | | SectionSubscript -> Integer -> Expr = '(i+j)/2_4' @@ -265,7 +265,7 @@ subroutine f12(x) !PARSE-TREE: | | | | | | LiteralConstant -> IntLiteralConstant = '2' !PARSE-TREE: | | bool = 'true' -subroutine f90(x, y) +subroutine f20(x, y) integer :: x(10) integer :: y integer, parameter :: p = 23 @@ -274,7 +274,7 @@ subroutine f90(x, y) !$omp end target end -!UNPARSE: SUBROUTINE f90 (x, y) +!UNPARSE: SUBROUTINE f20 (x, y) !UNPARSE: INTEGER x(10_4) !UNPARSE: INTEGER y !UNPARSE: INTEGER, PARAMETER :: p = 23_4 @@ -286,8 +286,8 @@ subroutine f90(x, y) !PARSE-TREE: OmpBeginBlockDirective !PARSE-TREE: | OmpBlockDirective -> llvm::omp::Directive = target !PARSE-TREE: | OmpClauseList -> OmpClause -> Map -> OmpMapClause -!PARSE-TREE: | | TypeModifier = Present -!PARSE-TREE: | | OmpIterator -> OmpIteratorSpecifier +!PARSE-TREE: | | Modifier -> OmpMapTypeModifier -> Value = Present +!PARSE-TREE: | | Modifier -> OmpIterator -> OmpIteratorSpecifier !PARSE-TREE: | | | TypeDeclarationStmt !PARSE-TREE: | | | | DeclarationTypeSpec -> IntrinsicTypeSpec -> IntegerTypeSpec -> !PARSE-TREE: | | | | EntityDecl @@ -299,24 +299,24 @@ subroutine f90(x, y) !PARSE-TREE: | | | | | Designator -> DataRef -> Name = 'y' !PARSE-TREE: | | | | Scalar -> Integer -> Expr = '23_4' !PARSE-TREE: | | | | | Designator -> DataRef -> Name = 'p' -!PARSE-TREE: | | OmpIteratorSpecifier -!PARSE-TREE: | | | TypeDeclarationStmt -!PARSE-TREE: | | | | DeclarationTypeSpec -> IntrinsicTypeSpec -> IntegerTypeSpec -> -!PARSE-TREE: | | | | EntityDecl -!PARSE-TREE: | | | | | Name = 'k' -!PARSE-TREE: | | | SubscriptTriplet -!PARSE-TREE: | | | | Scalar -> Integer -> Expr = 'i' -!PARSE-TREE: | | | | | Designator -> DataRef -> Name = 'i' -!PARSE-TREE: | | | | Scalar -> Integer -> Expr = 'j' -!PARSE-TREE: | | | | | Designator -> DataRef -> Name = 'j' -!PARSE-TREE: | | Type = To +!PARSE-TREE: | | | OmpIteratorSpecifier +!PARSE-TREE: | | | | TypeDeclarationStmt +!PARSE-TREE: | | | | | DeclarationTypeSpec -> IntrinsicTypeSpec -> IntegerTypeSpec -> +!PARSE-TREE: | | | | | EntityDecl +!PARSE-TREE: | | | | | | Name = 'k' +!PARSE-TREE: | | | | SubscriptTriplet +!PARSE-TREE: | | | | | Scalar -> Integer -> Expr = 'i' +!PARSE-TREE: | | | | | | Designator -> DataRef -> Name = 'i' +!PARSE-TREE: | | | | | Scalar -> Integer -> Expr = 'j' +!PARSE-TREE: | | | | | | Designator -> DataRef -> Name = 'j' +!PARSE-TREE: | | Modifier -> OmpMapType -> Value = To !PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> ArrayElement !PARSE-TREE: | | | DataRef -> Name = 'x' !PARSE-TREE: | | | SectionSubscript -> Integer -> Expr = 'k' !PARSE-TREE: | | | | Designator -> DataRef -> Name = 'k' !PARSE-TREE: | | bool = 'true' -subroutine f100(x, y) +subroutine f21(x, y) integer :: x(10) integer :: y integer, parameter :: p = 23 @@ -325,7 +325,7 @@ subroutine f100(x, y) !$omp end target end -!UNPARSE: SUBROUTINE f100 (x, y) +!UNPARSE: SUBROUTINE f21 (x, y) !UNPARSE: INTEGER x(10_4) !UNPARSE: INTEGER y !UNPARSE: INTEGER, PARAMETER :: p = 23_4 @@ -337,7 +337,42 @@ subroutine f100(x, y) !PARSE-TREE: OmpBeginBlockDirective !PARSE-TREE: | OmpBlockDirective -> llvm::omp::Directive = target !PARSE-TREE: | OmpClauseList -> OmpClause -> Map -> OmpMapClause -!PARSE-TREE: | | OmpMapperIdentifier -> Name = 'xx' -!PARSE-TREE: | | Type = From +!PARSE-TREE: | | Modifier -> OmpMapper -> Name = 'xx' +!PARSE-TREE: | | Modifier -> OmpMapType -> Value = From !PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x' +subroutine f22(x) + integer :: x(10) + !$omp target map(present, iterator(i = 1:10), always, from: x(i)) + x = x + 1 + !$omp end target +end + +!UNPARSE: SUBROUTINE f22 (x) +!UNPARSE: INTEGER x(10_4) +!UNPARSE: !$OMP TARGET MAP(PRESENT, ITERATOR(INTEGER i = 1_4:10_4), ALWAYS, FROM: x(i)) +!UNPARSE: x=x+1_4 +!UNPARSE: !$OMP END TARGET +!UNPARSE: END SUBROUTINE + +!PARSE-TREE: OmpBlockDirective -> llvm::omp::Directive = target +!PARSE-TREE: OmpClauseList -> OmpClause -> Map -> OmpMapClause +!PARSE-TREE: | Modifier -> OmpMapTypeModifier -> Value = Present +!PARSE-TREE: | Modifier -> OmpIterator -> 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: | Modifier -> OmpMapTypeModifier -> Value = Always +!PARSE-TREE: | Modifier -> OmpMapType -> Value = From +!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 index bb57270fc0bf9..03006ba37334f 100644 --- a/flang/test/Parser/OpenMP/target-update-to-clause.f90 +++ b/flang/test/Parser/OpenMP/target-update-to-clause.f90 @@ -28,7 +28,7 @@ subroutine f01(x) !PARSE-TREE: OmpSimpleStandaloneDirective -> llvm::omp::Directive = target update !PARSE-TREE: OmpClauseList -> OmpClause -> To -> OmpToClause -!PARSE-TREE: | Expectation = Present +!PARSE-TREE: | Modifier -> OmpExpectation -> Value = Present !PARSE-TREE: | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x' !PARSE-TREE: | bool = 'true' @@ -44,8 +44,8 @@ subroutine f02(x) !PARSE-TREE: OmpSimpleStandaloneDirective -> llvm::omp::Directive = target update !PARSE-TREE: OmpClauseList -> OmpClause -> To -> OmpToClause -!PARSE-TREE: | Expectation = Present -!PARSE-TREE: | OmpIterator -> OmpIteratorSpecifier +!PARSE-TREE: | Modifier -> OmpExpectation -> Value = Present +!PARSE-TREE: | Modifier -> OmpIterator -> OmpIteratorSpecifier !PARSE-TREE: | | TypeDeclarationStmt !PARSE-TREE: | | | DeclarationTypeSpec -> IntrinsicTypeSpec -> IntegerTypeSpec -> !PARSE-TREE: | | | EntityDecl @@ -73,8 +73,8 @@ subroutine f03(x) !PARSE-TREE: OmpSimpleStandaloneDirective -> llvm::omp::Directive = target update !PARSE-TREE: OmpClauseList -> OmpClause -> To -> OmpToClause -!PARSE-TREE: | Expectation = Present -!PARSE-TREE: | OmpIterator -> OmpIteratorSpecifier +!PARSE-TREE: | Modifier -> OmpExpectation -> Value = Present +!PARSE-TREE: | Modifier -> OmpIterator -> OmpIteratorSpecifier !PARSE-TREE: | | TypeDeclarationStmt !PARSE-TREE: | | | DeclarationTypeSpec -> IntrinsicTypeSpec -> IntegerTypeSpec -> !PARSE-TREE: | | | EntityDecl diff --git a/flang/test/Semantics/OpenMP/combined-constructs.f90 b/flang/test/Semantics/OpenMP/combined-constructs.f90 index 25893a47860f4..4f2a4a4f501b9 100644 --- a/flang/test/Semantics/OpenMP/combined-constructs.f90 +++ b/flang/test/Semantics/OpenMP/combined-constructs.f90 @@ -33,7 +33,7 @@ program main enddo !$omp end target parallel - !ERROR: A variable-category modifier is required + !ERROR: 'variable-category' modifier is required !$omp target parallel defaultmap(tofrom) do i = 1, N a(i) = 3.14 @@ -80,7 +80,7 @@ program main enddo !$omp end target parallel do - !ERROR: A variable-category modifier is required + !ERROR: 'variable-category' modifier is required !$omp target parallel do defaultmap(tofrom) do i = 1, N a(i) = 3.14 @@ -140,7 +140,7 @@ program main enddo !$omp end target teams - !ERROR: A variable-category modifier is required + !ERROR: 'variable-category' modifier is required !$omp target teams defaultmap(tofrom) do i = 1, N a(i) = 3.14 @@ -240,7 +240,7 @@ program main enddo !$omp end target teams distribute - !ERROR: A variable-category modifier is required + !ERROR: 'variable-category' modifier is required !$omp target teams distribute defaultmap(tofrom) do i = 1, N a(i) = 3.14 @@ -333,7 +333,7 @@ program main enddo !$omp end target teams distribute parallel do - !ERROR: A variable-category modifier is required + !ERROR: 'variable-category' modifier is required !$omp target teams distribute parallel do defaultmap(tofrom) do i = 1, N a(i) = 3.14 @@ -433,7 +433,7 @@ program main enddo !$omp end target teams distribute parallel do simd - !ERROR: A variable-category modifier is required + !ERROR: 'variable-category' modifier is required !$omp target teams distribute parallel do simd defaultmap(tofrom) do i = 1, N a(i) = 3.14 diff --git a/flang/test/Semantics/OpenMP/defaultmap-clause-v45.f90 b/flang/test/Semantics/OpenMP/defaultmap-clause-v45.f90 index 9cb91a71c5535..904fc306a31f4 100644 --- a/flang/test/Semantics/OpenMP/defaultmap-clause-v45.f90 +++ b/flang/test/Semantics/OpenMP/defaultmap-clause-v45.f90 @@ -1,7 +1,7 @@ !RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=45 -Werror subroutine f00 -!WARNING: A variable-category modifier is required +!WARNING: 'variable-category' modifier is required !$omp target defaultmap(tofrom) !$omp end target end diff --git a/flang/test/Semantics/OpenMP/from-clause-v45.f90 b/flang/test/Semantics/OpenMP/from-clause-v45.f90 index 9c418a400e548..98dff295c879d 100644 --- a/flang/test/Semantics/OpenMP/from-clause-v45.f90 +++ b/flang/test/Semantics/OpenMP/from-clause-v45.f90 @@ -8,21 +8,22 @@ subroutine f00(x) subroutine f01(x) integer :: x(10) -!WARNING: Iterator modifiers are 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(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 +!WARNING: 'expectation' 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: The PRESENT modifier is not supported in OpenMP v4.5, try -fopenmp-version=51 -!ERROR: Only one PRESENT modifier is allowed +!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 !$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 18139f04c35cf..70c00823d073e 100644 --- a/flang/test/Semantics/OpenMP/from-clause-v51.f90 +++ b/flang/test/Semantics/OpenMP/from-clause-v51.f90 @@ -2,13 +2,13 @@ subroutine f01(x) integer :: x(10) -!ERROR: Only one iterator-modifier is allowed +!ERROR: 'iterator' modifier cannot occur multiple times !$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 +!ERROR: 'expectation' modifier cannot occur multiple times !$omp target update from(present, present: x) end diff --git a/flang/test/Semantics/OpenMP/map-clause.f90 b/flang/test/Semantics/OpenMP/map-clause.f90 index efcef2571a04a..65ecbd9456464 100644 --- a/flang/test/Semantics/OpenMP/map-clause.f90 +++ b/flang/test/Semantics/OpenMP/map-clause.f90 @@ -1,4 +1,4 @@ -! RUN: %python %S/../test_errors.py %s %flang -fopenmp +! RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=52 ! Check OpenMP MAP clause validity. Section 5.8.3 OpenMP 5.2. subroutine sb(arr) diff --git a/flang/test/Semantics/OpenMP/map-modifiers.f90 b/flang/test/Semantics/OpenMP/map-modifiers.f90 index f863185d111e0..aae918a2f1f94 100644 --- a/flang/test/Semantics/OpenMP/map-modifiers.f90 +++ b/flang/test/Semantics/OpenMP/map-modifiers.f90 @@ -83,8 +83,16 @@ subroutine f19(x) subroutine f1a(x) integer :: x(10) -!ERROR: Only one iterator-modifier is allowed +!ERROR: 'iterator' modifier cannot occur multiple times !$omp target map(present, iterator(i = 1:2), iterator(j = 1:2), to: x(i + j)) x = x + 1 !$omp end target end + +subroutine f23(x) + integer :: x(10) +!ERROR: 'map-type' should be the last modifier + !$omp target map(present, from, iterator(i = 1:10): x(i)) + x = x + 1 + !$omp end target +end diff --git a/flang/test/Semantics/OpenMP/to-clause-v45.f90 b/flang/test/Semantics/OpenMP/to-clause-v45.f90 index 39e842492ef08..e4d8967ca14df 100644 --- a/flang/test/Semantics/OpenMP/to-clause-v45.f90 +++ b/flang/test/Semantics/OpenMP/to-clause-v45.f90 @@ -8,21 +8,22 @@ subroutine f00(x) subroutine f01(x) integer :: x(10) -!WARNING: Iterator modifiers are 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(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 +!WARNING: 'expectation' 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: The PRESENT modifier is not supported in OpenMP v4.5, try -fopenmp-version=51 -!ERROR: Only one PRESENT modifier is allowed +!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 !$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 d4f5f15efeb97..8abbca3bb07cd 100644 --- a/flang/test/Semantics/OpenMP/to-clause-v51.f90 +++ b/flang/test/Semantics/OpenMP/to-clause-v51.f90 @@ -2,13 +2,13 @@ subroutine f01(x) integer :: x(10) -!ERROR: Only one iterator-modifier is allowed +!ERROR: 'iterator' modifier cannot occur multiple times !$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 +!ERROR: 'expectation' modifier cannot occur multiple times !$omp target update to(present, present: x) end