diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h --- a/flang/include/flang/Parser/dump-parse-tree.h +++ b/flang/include/flang/Parser/dump-parse-tree.h @@ -456,6 +456,9 @@ NODE(parser, OmpDefaultmapClause) NODE_ENUM(OmpDefaultmapClause, ImplicitBehavior) NODE_ENUM(OmpDefaultmapClause, VariableCategory) + NODE(parser, OmpIteratorSpecifier) + NODE(parser, OmpIteratorSpecifierList) + NODE(parser, OmpIterator) NODE(parser, OmpDependClause) NODE(OmpDependClause, InOut) NODE(OmpDependClause, Sink) @@ -520,6 +523,8 @@ NODE(parser, OpenMPDeclareReductionConstruct) NODE(parser, OpenMPDeclareSimdConstruct) NODE(parser, OpenMPDeclareTargetConstruct) + NODE(parser, OmpFlushMemoryClause) + NODE_ENUM(OmpFlushMemoryClause, FlushMemoryOrder) NODE(parser, OpenMPFlushConstruct) NODE(parser, OpenMPLoopConstruct) NODE(parser, OpenMPSimpleStandaloneConstruct) diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h --- a/flang/include/flang/Parser/parse-tree.h +++ b/flang/include/flang/Parser/parse-tree.h @@ -3276,7 +3276,28 @@ WRAPPER_CLASS(PauseStmt, std::optional); -// Parse tree nodes for OpenMP 4.5 directives and clauses +// Parse tree nodes for OpenMP 4.5/5.0 directives and clauses + +// 2.1.6 Iterators [OpenMP 5.0] +// iterators-specifier -> [ iterator-type ] identifier = range-specification +// iterator-type -> integer type +// range-specification -> begin:end[:step] +struct OmpIteratorSpecifier { + TUPLE_CLASS_BOILERPLATE(OmpIteratorSpecifier); + CharBlock source; + using Bounds = LoopBounds; + std::tuple, Bounds> t; +}; + +WRAPPER_CLASS(OmpIteratorSpecifierList, std::list); + +// 2.1.6 iterators -> iterator(iterators-definition) +// iterators-definition -> iterator-specifier [, iterators-definition ] +struct OmpIterator { + TUPLE_CLASS_BOILERPLATE(OmpIterator); + CharBlock source; + std::tuple t; +}; // 2.5 proc-bind-clause -> PROC_BIND (MASTER | CLOSE | SPREAD) struct OmpProcBindClause { @@ -3404,34 +3425,43 @@ std::tuple> t; }; -// 2.13.9 depend-vec-length -> +/- non-negative-constant +// 2.18.11 Depend Clause [OpenMP 5.0] +// 2.18.11 depend-vec-length -> +/- non-negative-constant struct OmpDependSinkVecLength { TUPLE_CLASS_BOILERPLATE(OmpDependSinkVecLength); std::tuple t; }; -// 2.13.9 depend-vec -> iterator [+/- depend-vec-length],...,iterator[...] +// 2.18.11 depend-vec -> iterator [+/- depend-vec-length],...,iterator[...] struct OmpDependSinkVec { TUPLE_CLASS_BOILERPLATE(OmpDependSinkVec); std::tuple> t; }; -// 2.13.9 depend-type -> IN | OUT | INOUT | SOURCE | SINK +// 2.18.11 dependence-type -> IN | OUT | INOUT | MUTEXINOUTSET | INOUTSET | +// DEPOBJ struct OmpDependenceType { - ENUM_CLASS(Type, In, Out, Inout, Source, Sink) + ENUM_CLASS(Type, In, Out, Inout, Mutexinoutset, Inoutset, Depobj) WRAPPER_CLASS_BOILERPLATE(OmpDependenceType, Type); }; -// 2.13.9 depend-clause -> DEPEND (((IN | OUT | INOUT) : variable-name-list) | -// SOURCE | SINK : depend-vec) +// 2.18.11 depend-clause -> DEPEND (([ITERATOR(iterators-definition),] +// (IN | OUT | INOUT | INOUTSET | +// MUTEXINOUTSET | DEPOBJ) : +// variable-name-list) | +// SOURCE | +// SINK : depend-vec) struct OmpDependClause { UNION_CLASS_BOILERPLATE(OmpDependClause); EMPTY_CLASS(Source); WRAPPER_CLASS(Sink, std::list); struct InOut { TUPLE_CLASS_BOILERPLATE(InOut); - std::tuple> t; + std::tuple, OmpDependenceType, + std::list> + t; }; + CharBlock source; std::variant u; }; @@ -3716,11 +3746,23 @@ std::tuple> t; }; -// 2.13.7 flush -> FLUSH [(variable-name-list)] +// 2.18.8 Flush Construct [OpenMP 5.0] +// memory-order-clause -> acq_rel +// release +// acquire +struct OmpFlushMemoryClause { + ENUM_CLASS(FlushMemoryOrder, AcqRel, Release, Acquire) + WRAPPER_CLASS_BOILERPLATE(OmpFlushMemoryClause, FlushMemoryOrder); + CharBlock source; +}; + +// 2.18.8 flush -> FLUSH [memory-order-clause] [(variable-name-list)] struct OpenMPFlushConstruct { TUPLE_CLASS_BOILERPLATE(OpenMPFlushConstruct); CharBlock source; - std::tuple> t; + std::tuple, + std::optional> + t; }; struct OmpSimpleStandaloneDirective { diff --git a/flang/include/flang/Semantics/scope.h b/flang/include/flang/Semantics/scope.h --- a/flang/include/flang/Semantics/scope.h +++ b/flang/include/flang/Semantics/scope.h @@ -56,7 +56,7 @@ public: ENUM_CLASS(Kind, Global, Module, MainProgram, Subprogram, BlockData, - DerivedType, Block, Forall, ImpliedDos) + DerivedType, Block, Forall, ImpliedDos, OmpIterators) using ImportKind = common::ImportKind; // Create the Global scope -- the root of the scope tree diff --git a/flang/lib/Parser/expr-parsers.h b/flang/lib/Parser/expr-parsers.h --- a/flang/lib/Parser/expr-parsers.h +++ b/flang/lib/Parser/expr-parsers.h @@ -101,5 +101,9 @@ return construct>( doVariable / "=", p / ",", p, maybe("," >> p)); } +template inline constexpr auto ompLoopBounds(const PA &p) { + return construct>( + doVariable / "=", p / ":", p, maybe(":" >> p)); +} } // namespace Fortran::parser #endif diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp --- a/flang/lib/Parser/openmp-parsers.cpp +++ b/flang/lib/Parser/openmp-parsers.cpp @@ -27,6 +27,19 @@ return sourced(construct(x)); } +// 2.1.6 ITERATOR(iterators-definition) +// iterators-definition -> iterator-specifier [, iterators-definition ] +// iterator-specifier -> [ iterator-type ] identifier = +// range-specification +TYPE_PARSER(sourced(construct( + maybe(integerTypeSpec / "::"), ompLoopBounds(scalarIntExpr)))) + +TYPE_PARSER(construct( + many(maybe(","_tok) >> Parser{}))) + +TYPE_PARSER(sourced(construct(verbatim("ITERATOR"_tok), + parenthesized(Parser{})))) + // OpenMP Clauses // 2.15.3.1 DEFAULT (PRIVATE | FIRSTPRIVATE | SHARED | NONE) TYPE_PARSER(construct( @@ -108,7 +121,13 @@ TYPE_PARSER(construct( Parser{} / ":", nonemptyList(designator))) -// 2.13.9 DEPEND (SOURCE | SINK : vec | (IN | OUT | INOUT) : list +// 2.18.11 DEPEND (source-dependence | sink-dependence | other-dependence) +// source-dependence -> SOURCE +// sink-dependence -> SINK : vec +// other-dependence -> dependence-modifier dependence-type : list +// dependence-modifier -> [ITERATOR(iterators-definition), ] +// dependence-type -> IN | OUT | INOUT | MUTEXINOUTSET | INOUTSET | +// DEPOBJ TYPE_PARSER(construct( Parser{}, scalarIntConstantExpr)) @@ -117,16 +136,21 @@ TYPE_PARSER( construct("IN"_id >> pure(OmpDependenceType::Type::In) || + "OUT" >> pure(OmpDependenceType::Type::Out) || "INOUT" >> pure(OmpDependenceType::Type::Inout) || - "OUT" >> pure(OmpDependenceType::Type::Out))) + "MUTEXINOUTSET" >> pure(OmpDependenceType::Type::Mutexinoutset) || + "INOUTSET" >> pure(OmpDependenceType::Type::Inoutset) || + "DEPOBJ" >> pure(OmpDependenceType::Type::Depobj))) TYPE_CONTEXT_PARSER("Omp Depend clause"_en_US, construct(construct( "SINK :" >> nonemptyList(Parser{}))) || construct( construct("SOURCE"_tok)) || - construct(construct( - Parser{}, ":" >> nonemptyList(designator)))) + sourced(construct( + construct(maybe(Parser{}), + maybe(","_tok) >> Parser{}, + ":" >> nonemptyList(designator))))) // 2.15.3.7 LINEAR (linear-list: linear-step) // linear-list -> list | modifier(list) @@ -299,8 +323,18 @@ Parser{}, maybe("IF" >> parenthesized(scalarLogicalExpr))))) // 2.13.7 Flush construct -TYPE_PARSER(sourced(construct( - verbatim("FLUSH"_tok), maybe(parenthesized(Parser{}))))) +// flush -> FLUSH [memory-order-clause] [(variable-name-list)] +// memory-order-clause -> acq_rel +// release +// acquire +TYPE_PARSER(sourced(construct( + "ACQ_REL" >> pure(OmpFlushMemoryClause::FlushMemoryOrder::AcqRel) || + "RELEASE" >> pure(OmpFlushMemoryClause::FlushMemoryOrder::Release) || + "ACQUIRE" >> pure(OmpFlushMemoryClause::FlushMemoryOrder::Acquire)))) + +TYPE_PARSER(sourced(construct(verbatim("FLUSH"_tok), + maybe(Parser{}), + maybe(parenthesized(Parser{}))))) // Simple Standalone Directives TYPE_PARSER(sourced(construct(first( diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp --- a/flang/lib/Parser/unparse.cpp +++ b/flang/lib/Parser/unparse.cpp @@ -1778,6 +1778,18 @@ Walk(std::get(x.t)); } // OpenMP Clauses & Directives + void Unparse(const OmpIteratorSpecifier &x) { + Walk(std::get>(x.t), "::"); + const auto &bounds{std::get(x.t)}; + Walk(bounds.name), Put('='); + Walk(bounds.lower), Put(':'), Walk(bounds.upper), Walk(":", bounds.step); + } + void Unparse(const OmpIteratorSpecifierList &x) { Walk(" ", x.v, ", "); } + void Unparse(const OmpIterator &x) { + Word("ITERATOR("); + Walk(std::get(x.t)); + Put(")"); + } void Unparse(const OmpObject &x) { std::visit(common::visitors{ [&](const Designator &y) { Walk(y); }, @@ -1842,6 +1854,7 @@ } void Unparse(const OmpDependClause::InOut &x) { Put("("); + Walk(std::get>(x.t), ", "); Walk(std::get(x.t)); Put(":"); Walk(std::get>(x.t), ","); @@ -2359,10 +2372,24 @@ Put("\n"); EndOpenMP(); } + void Unparse(const OmpFlushMemoryClause &x) { + switch (x.v) { + case OmpFlushMemoryClause::FlushMemoryOrder::AcqRel: + Word("ACQ_REL "); + break; + case OmpFlushMemoryClause::FlushMemoryOrder::Release: + Word("RELEASE "); + break; + case OmpFlushMemoryClause::FlushMemoryOrder::Acquire: + Word("ACQUIRE "); + break; + } + } void Unparse(const OpenMPFlushConstruct &x) { BeginOpenMP(); - Word("!$OMP FLUSH"); - Walk("(", std::get>(x.t), ")"); + Word("!$OMP FLUSH "); + Walk(std::get>(x.t)); + Walk(" (", std::get>(x.t), ")"); Put("\n"); EndOpenMP(); } diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -668,6 +668,8 @@ case parser::OmpSimpleStandaloneDirective::Directive::Taskwait: { // 2.13.4 taskwait PushContext(dir.source, OmpDirective::TASKWAIT); + OmpClauseSet allowed{OmpClause::DEPEND}; + SetContextAllowed(allowed); } break; case parser::OmpSimpleStandaloneDirective::Directive::Taskyield: { // 2.9.4 taskyield diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp --- a/flang/lib/Semantics/resolve-names.cpp +++ b/flang/lib/Semantics/resolve-names.cpp @@ -1083,6 +1083,9 @@ static bool NeedsScope(const parser::OpenMPBlockConstruct &); + bool Pre(const parser::OmpIteratorSpecifier &); + bool Pre(const parser::OmpDependClause &); + void Post(const parser::OmpDependClause &); bool Pre(const parser::OpenMPBlockConstruct &); void Post(const parser::OpenMPBlockConstruct &); bool Pre(const parser::OmpBeginBlockDirective &x) { @@ -6373,6 +6376,34 @@ bool pushedScope_{false}; }; +bool OmpVisitor::Pre(const parser::OmpIteratorSpecifier &x) { + auto &type{std::get>(x.t)}; + auto &bounds{std::get(x.t)}; + DeclareStatementEntity(bounds.name.thing.thing, type); + Walk(bounds); + return false; +} + +bool OmpVisitor::Pre(const parser::OmpDependClause &x) { + messageHandler().set_currStmtSource(x.source); + std::visit( + common::visitors{ + [&](const parser::OmpDependClause::Source &) {}, + [&](const parser::OmpDependClause::Sink &) {}, + [&](const parser::OmpDependClause::InOut &y) { + PushScope(Scope::Kind::OmpIterators, nullptr); + Walk(y); + PopScope(); + }, + }, + x.u); + return false; +} + +void OmpVisitor::Post(const parser::OmpDependClause &) { + messageHandler().set_currStmtSource(std::nullopt); +} + bool OmpAttributeVisitor::Pre(const parser::OpenMPBlockConstruct &x) { const auto &beginBlockDir{std::get(x.t)}; const auto &beginDir{std::get(beginBlockDir.t)}; diff --git a/flang/test/Semantics/omp-clause-validity01.f90 b/flang/test/Semantics/omp-clause-validity01.f90 --- a/flang/test/Semantics/omp-clause-validity01.f90 +++ b/flang/test/Semantics/omp-clause-validity01.f90 @@ -10,6 +10,7 @@ integer :: b = 128 integer :: c = 32 + integer :: val = 2 integer, parameter :: num = 16 real(8) :: arrayA(256), arrayB(512) @@ -396,6 +397,10 @@ !$omp taskyield !$omp barrier !$omp taskwait + !$omp taskwait depend(source) + !ERROR: Internal: no symbol found for 'i' + !$omp taskwait depend(sink:i-1) + !$omp taskwait depend(iterator(integer :: it=1_4:100:2), IN:arrayA(it)) ! !$omp target enter data map(to:arrayA) map(alloc:arrayB) ! !$omp target update from(arrayA) to(arrayB) ! !$omp target exit data map(from:arrayA) map(delete:arrayB) @@ -403,6 +408,10 @@ !ERROR: Internal: no symbol found for 'i' !$omp ordered depend(sink:i-1) !$omp flush (c) + !$omp flush acq_rel + !$omp flush release + !$omp flush acquire + !$omp flush release (c) !$omp cancel DO !$omp cancellation point parallel @@ -445,6 +454,23 @@ a = 3.14 !$omp end task + !$OMP TASK DEPEND(ITERATOR( it=1_4:100:2), IN:arrayA(it)) + a = 3.14 + !$OMP END TASK + + !$OMP TASK DEPEND(ITERATOR(integer :: it=1_4:100:2), IN:arrayA(it)) + a = 3.14 + !$OMP END TASK + + !$omp task depend(in: b) depend(mutexinoutset: c) + a = 3.14 + !$omp end task + + !$omp task depend(depobj: obj) + a = 3.14 + !$omp end task + + ! 2.9.3 taskloop-simd-clause -> taskloop-clause | ! simd-clause