diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h index 31ad1b7c6ce5b..67f7e1aac40ed 100644 --- a/flang/include/flang/Parser/dump-parse-tree.h +++ b/flang/include/flang/Parser/dump-parse-tree.h @@ -517,6 +517,7 @@ class ParseTreeDumper { NODE_ENUM(OmpTaskDependenceType, Type) NODE(parser, OmpDependSinkVec) NODE(parser, OmpDependSinkVecLength) + NODE(parser, OmpDestroyClause) NODE(parser, OmpEndAllocators) NODE(parser, OmpEndAtomic) NODE(parser, OmpEndBlockDirective) @@ -571,6 +572,7 @@ class ParseTreeDumper { NODE_ENUM(OmpDeviceClause, DeviceModifier) NODE(parser, OmpDeviceTypeClause) NODE_ENUM(OmpDeviceTypeClause, Type) + NODE(parser, OmpUpdateClause) NODE(parser, OmpScheduleModifier) NODE(OmpScheduleModifier, Modifier1) NODE(OmpScheduleModifier, Modifier2) @@ -609,6 +611,7 @@ class ParseTreeDumper { NODE(parser, OmpAtomicClauseList) NODE(parser, OmpAtomicDefaultMemOrderClause) NODE_ENUM(common, OmpAtomicDefaultMemOrderType) + NODE(parser, OpenMPDepobjConstruct) NODE(parser, OpenMPFlushConstruct) NODE(parser, OpenMPLoopConstruct) NODE(parser, OpenMPExecutableAllocate) diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h index 174f4c631e9d4..13c3353512208 100644 --- a/flang/include/flang/Parser/parse-tree.h +++ b/flang/include/flang/Parser/parse-tree.h @@ -3447,7 +3447,7 @@ WRAPPER_CLASS(OmpObjectList, std::list); // MUTEXINOUTSET | DEPOBJ | // since 5.0 // INOUTSET // since 5.2 struct OmpTaskDependenceType { - ENUM_CLASS(Type, In, Out, Inout, Source, Sink) + ENUM_CLASS(Type, In, Out, Inout, Source, Sink, Depobj) WRAPPER_CLASS_BOILERPLATE(OmpTaskDependenceType, Type); }; @@ -3527,19 +3527,6 @@ struct OmpDefaultmapClause { std::tuple> t; }; -// device([ device-modifier :] scalar-integer-expression) -struct OmpDeviceClause { - TUPLE_CLASS_BOILERPLATE(OmpDeviceClause); - ENUM_CLASS(DeviceModifier, Ancestor, Device_Num) - std::tuple, ScalarIntExpr> t; -}; - -// device_type(any | host | nohost) -struct OmpDeviceTypeClause { - ENUM_CLASS(Type, Any, Host, Nohost) - WRAPPER_CLASS_BOILERPLATE(OmpDeviceTypeClause, Type); -}; - // 2.13.9 depend-vec-length -> +/- non-negative-constant struct OmpDependSinkVecLength { TUPLE_CLASS_BOILERPLATE(OmpDependSinkVecLength); @@ -3561,6 +3548,8 @@ struct OmpDependSinkVec { // // depend-modifier -> iterator-modifier // since 5.0 struct OmpDependClause { + OmpTaskDependenceType::Type GetDepType() const; + UNION_CLASS_BOILERPLATE(OmpDependClause); EMPTY_CLASS(Source); WRAPPER_CLASS(Sink, std::list); @@ -3573,6 +3562,26 @@ struct OmpDependClause { std::variant u; }; +// Ref: [5.0:254-255], [5.1:287-288], [5.2:73] +// +// destroy-clause -> +// DESTROY | // since 5.0, until 5.2 +// DESTROY(variable) // since 5.2 +WRAPPER_CLASS(OmpDestroyClause, OmpObject); + +// device([ device-modifier :] scalar-integer-expression) +struct OmpDeviceClause { + TUPLE_CLASS_BOILERPLATE(OmpDeviceClause); + ENUM_CLASS(DeviceModifier, Ancestor, Device_Num) + std::tuple, ScalarIntExpr> t; +}; + +// device_type(any | host | nohost) +struct OmpDeviceTypeClause { + ENUM_CLASS(Type, Any, Host, Nohost) + WRAPPER_CLASS_BOILERPLATE(OmpDeviceTypeClause, Type); +}; + // OMP 5.2 12.6.1 grainsize-clause -> grainsize ([prescriptiveness :] value) struct OmpGrainsizeClause { TUPLE_CLASS_BOILERPLATE(OmpGrainsizeClause); @@ -3716,6 +3725,11 @@ struct OmpNumTasksClause { std::tuple, ScalarIntExpr> t; }; +// Ref: [5.0:254-255], [5.1:287-288], [5.2:321-322] +// +// update-clause -> UPDATE(task-dependence-type) // since 5.0 +WRAPPER_CLASS(OmpUpdateClause, OmpTaskDependenceType); + // OpenMP Clauses struct OmpClause { UNION_CLASS_BOILERPLATE(OmpClause); @@ -4023,6 +4037,18 @@ struct OpenMPCancelConstruct { std::tuple> t; }; +// Ref: [5.0:254-255], [5.1:287-288], [5.2:322-323] +// +// depobj-construct -> DEPOBJ(depend-object) depobj-clause // since 5.0 +// depobj-clause -> depend-clause | // until 5.2 +// destroy-clause | +// update-clause +struct OpenMPDepobjConstruct { + TUPLE_CLASS_BOILERPLATE(OpenMPDepobjConstruct); + CharBlock source; + std::tuple t; +}; + // 2.17.8 flush -> FLUSH [memory-order-clause] [(variable-name-list)] struct OpenMPFlushConstruct { TUPLE_CLASS_BOILERPLATE(OpenMPFlushConstruct); @@ -4047,7 +4073,8 @@ struct OpenMPStandaloneConstruct { UNION_CLASS_BOILERPLATE(OpenMPStandaloneConstruct); CharBlock source; std::variant + OpenMPCancelConstruct, OpenMPCancellationPointConstruct, + OpenMPDepobjConstruct> u; }; diff --git a/flang/include/flang/Semantics/symbol.h b/flang/include/flang/Semantics/symbol.h index 0767d8ea84bc6..b9512f33eaacd 100644 --- a/flang/include/flang/Semantics/symbol.h +++ b/flang/include/flang/Semantics/symbol.h @@ -755,7 +755,7 @@ class Symbol { OmpDeclarativeAllocateDirective, OmpExecutableAllocateDirective, OmpDeclareSimd, OmpDeclareTarget, OmpThreadprivate, OmpDeclareReduction, OmpFlushed, OmpCriticalLock, OmpIfSpecified, OmpNone, OmpPreDetermined, - OmpImplicit); + OmpImplicit, OmpDependObject); using Flags = common::EnumSet; const Scope &owner() const { return *owner_; } diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp index 7c254ce673855..8eb1fdb470917 100644 --- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp +++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp @@ -137,6 +137,8 @@ genDependKindAttr(fir::FirOpBuilder &firOpBuilder, case omp::clause::Depend::TaskDependenceType::Mutexinoutset: case omp::clause::Depend::TaskDependenceType::Inoutset: case omp::clause::Depend::TaskDependenceType::Depobj: + case omp::clause::Depend::TaskDependenceType::Sink: + case omp::clause::Depend::TaskDependenceType::Source: llvm_unreachable("unhandled parser task dependence type"); break; } diff --git a/flang/lib/Lower/OpenMP/Clauses.cpp b/flang/lib/Lower/OpenMP/Clauses.cpp index 9483f643acd55..45b89de023a4b 100644 --- a/flang/lib/Lower/OpenMP/Clauses.cpp +++ b/flang/lib/Lower/OpenMP/Clauses.cpp @@ -338,6 +338,27 @@ ReductionOperator makeReductionOperator(const parser::OmpReductionOperator &inp, inp.u); } +clause::TaskDependenceType +makeDepType(const parser::OmpTaskDependenceType &inp) { + switch (inp.v) { + case parser::OmpTaskDependenceType::Type::Depobj: + return clause::TaskDependenceType::Depobj; + case parser::OmpTaskDependenceType::Type::In: + return clause::TaskDependenceType::In; + case parser::OmpTaskDependenceType::Type::Inout: + return clause::TaskDependenceType::Inout; + // Inoutset // missing-in-parser + // Mutexinoutset // missing-in-parser + case parser::OmpTaskDependenceType::Type::Out: + return clause::TaskDependenceType::Out; + case parser::OmpTaskDependenceType::Type::Sink: + return clause::TaskDependenceType::Sink; + case parser::OmpTaskDependenceType::Type::Source: + return clause::TaskDependenceType::Source; + } + llvm_unreachable("Unexpected dependence type"); +} + // -------------------------------------------------------------------- // Actual clauses. Each T (where tomp::T exists in ClauseT) has its "make". @@ -554,18 +575,6 @@ Depend make(const parser::OmpClause::Depend &inp, // Iteration is the equivalent of parser::OmpDependSinkVec using Iteration = Doacross::Vector::value_type; // LoopIterationT - CLAUSET_ENUM_CONVERT( // - convert1, parser::OmpTaskDependenceType::Type, Depend::TaskDependenceType, - // clang-format off - MS(In, In) - MS(Out, Out) - MS(Inout, Inout) - // MS(, Mutexinoutset) // missing-in-parser - // MS(, Inputset) // missing-in-parser - // MS(, Depobj) // missing-in-parser - // clang-format on - ); - return Depend{Fortran::common::visit( // common::visitors{ // Doacross @@ -602,7 +611,7 @@ Depend make(const parser::OmpClause::Depend &inp, auto &&maybeIter = maybeApply( [&](auto &&s) { return makeIterator(s, semaCtx); }, t0); - return Depend::DepType{{/*TaskDependenceType=*/convert1(t1.v), + return Depend::DepType{{/*TaskDependenceType=*/makeDepType(t1), /*Iterator=*/std::move(maybeIter), /*LocatorList=*/makeObjects(t2, semaCtx)}}; }, @@ -614,8 +623,14 @@ Depend make(const parser::OmpClause::Depend &inp, Destroy make(const parser::OmpClause::Destroy &inp, semantics::SemanticsContext &semaCtx) { - // inp -> empty - llvm_unreachable("Empty: destroy"); + // inp.v -> std::optional + auto &&maybeObject = maybeApply( + [&](const parser::OmpDestroyClause &c) { + return makeObject(c.v, semaCtx); + }, + inp.v); + + return Destroy{/*DestroyVar=*/std::move(maybeObject)}; } Detach make(const parser::OmpClause::Detach &inp, @@ -1279,8 +1294,8 @@ Uniform make(const parser::OmpClause::Uniform &inp, Update make(const parser::OmpClause::Update &inp, semantics::SemanticsContext &semaCtx) { - // inp -> empty - return Update{/*TaskDependenceType=*/std::nullopt}; + // inp.v -> parser::OmpUpdateClause + return Update{/*TaskDependenceType=*/makeDepType(inp.v.v)}; } Use make(const parser::OmpClause::Use &inp, diff --git a/flang/lib/Lower/OpenMP/Clauses.h b/flang/lib/Lower/OpenMP/Clauses.h index 1e911a2046857..51180ebfe5745 100644 --- a/flang/lib/Lower/OpenMP/Clauses.h +++ b/flang/lib/Lower/OpenMP/Clauses.h @@ -152,6 +152,7 @@ using IteratorSpecifier = tomp::type::IteratorSpecifierT; using DefinedOperator = tomp::type::DefinedOperatorT; using ProcedureDesignator = tomp::type::ProcedureDesignatorT; using ReductionOperator = tomp::type::ReductionIdentifierT; +using TaskDependenceType = tomp::type::TaskDependenceType; // "Requires" clauses are handled early on, and the aggregated information // is stored in the Symbol details of modules, programs, and subprograms. diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp index 01a40d6e2204e..954d6b8d122f4 100644 --- a/flang/lib/Lower/OpenMP/OpenMP.cpp +++ b/flang/lib/Lower/OpenMP/OpenMP.cpp @@ -2699,6 +2699,21 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable, TODO(converter.getCurrentLocation(), "OpenMPCancelConstruct"); } +static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable, + semantics::SemanticsContext &semaCtx, + lower::pft::Evaluation &eval, + const parser::OpenMPDepobjConstruct &construct) { + // These values will be ignored until the construct itself is implemented, + // but run them anyway for the sake of testing (via a Todo test). + auto &ompObj = std::get(construct.t); + const Object &depObj = makeObject(ompObj, semaCtx); + Clause clause = makeClause(std::get(construct.t), semaCtx); + (void)depObj; + (void)clause; + + TODO(converter.getCurrentLocation(), "OpenMPDepobjConstruct"); +} + static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable, semantics::SemanticsContext &semaCtx, lower::pft::Evaluation &eval, diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp index 598439cbee87e..eea4aa5896a1b 100644 --- a/flang/lib/Parser/openmp-parsers.cpp +++ b/flang/lib/Parser/openmp-parsers.cpp @@ -366,9 +366,12 @@ TYPE_PARSER( construct(name, maybe(Parser{}))) TYPE_PARSER(construct( + "DEPOBJ" >> pure(OmpTaskDependenceType::Type::Depobj) || "IN"_id >> pure(OmpTaskDependenceType::Type::In) || "INOUT" >> pure(OmpTaskDependenceType::Type::Inout) || - "OUT" >> pure(OmpTaskDependenceType::Type::Out))) + "OUT" >> pure(OmpTaskDependenceType::Type::Out) || + "SINK" >> pure(OmpTaskDependenceType::Type::Sink) || + "SOURCE" >> pure(OmpTaskDependenceType::Type::Source))) TYPE_CONTEXT_PARSER("Omp Depend clause"_en_US, construct(construct( @@ -454,6 +457,9 @@ TYPE_PARSER( parenthesized(Parser{}))) || "DEPEND" >> construct(construct( parenthesized(Parser{}))) || + "DESTROY" >> + construct(construct(maybe(parenthesized( + construct(Parser{}))))) || "DEVICE" >> construct(construct( parenthesized(Parser{}))) || "DEVICE_TYPE" >> construct(construct( @@ -560,7 +566,9 @@ TYPE_PARSER( construct(construct()) || "UNIFORM" >> construct(construct( parenthesized(nonemptyList(name)))) || - "UNTIED" >> construct(construct())) + "UNTIED" >> construct(construct()) || + "UPDATE" >> construct(construct( + parenthesized(Parser{})))) // [Clause, [Clause], ...] TYPE_PARSER(sourced(construct( @@ -673,6 +681,9 @@ TYPE_PARSER(sourced(construct( TYPE_PARSER(sourced(construct( many(maybe(","_tok) >> sourced(Parser{}))))) +TYPE_PARSER(sourced(construct(verbatim("DEPOBJ"_tok), + parenthesized(Parser{}), sourced(Parser{})))) + TYPE_PARSER(sourced(construct(verbatim("FLUSH"_tok), many(maybe(","_tok) >> sourced(Parser{})), maybe(parenthesized(Parser{}))))) @@ -697,7 +708,8 @@ TYPE_PARSER( construct(Parser{}) || construct(Parser{}) || construct( - Parser{})) / + Parser{}) || + construct(Parser{})) / endOfLine) // Directives enclosing structured-block diff --git a/flang/lib/Parser/parse-tree.cpp b/flang/lib/Parser/parse-tree.cpp index 948ad04a091a8..60aef1666e9ba 100644 --- a/flang/lib/Parser/parse-tree.cpp +++ b/flang/lib/Parser/parse-tree.cpp @@ -252,6 +252,23 @@ CharBlock Variable::GetSource() const { llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Name &x) { return os << x.ToString(); } + +OmpTaskDependenceType::Type OmpDependClause::GetDepType() const { + return common::visit( + common::visitors{ + [&](const parser::OmpDependClause::Source &) { + return parser::OmpTaskDependenceType::Type::Source; + }, + [&](const parser::OmpDependClause::Sink &) { + return parser::OmpTaskDependenceType::Type::Sink; + }, + [&](const parser::OmpDependClause::InOut &y) { + return std::get(y.t).v; + }, + }, + u); +} + } // namespace Fortran::parser template static llvm::omp::Clause getClauseIdForClass(C &&) { diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp index 39fcb61609e33..32fe530e16f63 100644 --- a/flang/lib/Parser/unparse.cpp +++ b/flang/lib/Parser/unparse.cpp @@ -2215,11 +2215,9 @@ class UnparseVisitor { Walk(std::get>(x.t)); } void Unparse(const OmpDependClause::InOut &x) { - Put("("); Walk(std::get(x.t)); Put(":"); Walk(std::get(x.t)); - Put(")"); } bool Pre(const OmpDependClause &x) { return common::visit( @@ -2706,6 +2704,16 @@ class UnparseVisitor { }, x.u); } + void Unparse(const OpenMPDepobjConstruct &x) { + BeginOpenMP(); + Word("!$OMP DEPOBJ"); + Put("("); + Walk(std::get(x.t)); + Put(") "); + Walk(std::get(x.t)); + Put("\n"); + EndOpenMP(); + } void Unparse(const OpenMPFlushConstruct &x) { BeginOpenMP(); Word("!$OMP FLUSH "); diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp index 8f3eb9fefee67..c813100b4b16c 100644 --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -1261,6 +1261,39 @@ void OmpStructureChecker::Leave(const parser::OpenMPDeclareSimdConstruct &) { dirContext_.pop_back(); } +void OmpStructureChecker::Enter(const parser::OpenMPDepobjConstruct &x) { + const auto &dir{std::get(x.t)}; + PushContextAndClauseSets(dir.source, llvm::omp::Directive::OMPD_depobj); + + // [5.2:73:27-28] + // If the destroy clause appears on a depobj construct, destroy-var must + // refer to the same depend object as the depobj argument of the construct. + auto &clause{std::get(x.t)}; + if (clause.Id() == llvm::omp::Clause::OMPC_destroy) { + auto getSymbol{[&](const parser::OmpObject &obj) { + return common::visit( + [&](auto &&s) { return GetLastName(s).symbol; }, obj.u); + }}; + + auto &wrapper{std::get(clause.u)}; + if (const std::optional &destroy{wrapper.v}) { + const Symbol *constrSym{getSymbol(std::get(x.t))}; + const Symbol *clauseSym{getSymbol(destroy->v)}; + assert(constrSym && "Unresolved depobj construct symbol"); + assert(clauseSym && "Unresolved destroy symbol on depobj construct"); + if (constrSym != clauseSym) { + context_.Say(x.source, + "The DESTROY clause must refer to the same object as the " + "DEPOBJ construct"_err_en_US); + } + } + } +} + +void OmpStructureChecker::Leave(const parser::OpenMPDepobjConstruct &x) { + dirContext_.pop_back(); +} + void OmpStructureChecker::Enter(const parser::OpenMPRequiresConstruct &x) { const auto &dir{std::get(x.t)}; PushContextAndClauseSets(dir.source, llvm::omp::Directive::OMPD_requires); @@ -2476,7 +2509,6 @@ CHECK_SIMPLE_CLAUSE(Capture, OMPC_capture) CHECK_SIMPLE_CLAUSE(Contains, OMPC_contains) CHECK_SIMPLE_CLAUSE(Default, OMPC_default) CHECK_SIMPLE_CLAUSE(Depobj, OMPC_depobj) -CHECK_SIMPLE_CLAUSE(Destroy, OMPC_destroy) CHECK_SIMPLE_CLAUSE(Detach, OMPC_detach) CHECK_SIMPLE_CLAUSE(DeviceType, OMPC_device_type) CHECK_SIMPLE_CLAUSE(DistSchedule, OMPC_dist_schedule) @@ -2519,7 +2551,6 @@ CHECK_SIMPLE_CLAUSE(Uniform, OMPC_uniform) CHECK_SIMPLE_CLAUSE(Unknown, OMPC_unknown) CHECK_SIMPLE_CLAUSE(Untied, OMPC_untied) CHECK_SIMPLE_CLAUSE(UsesAllocators, OMPC_uses_allocators) -CHECK_SIMPLE_CLAUSE(Update, OMPC_update) CHECK_SIMPLE_CLAUSE(Write, OMPC_write) CHECK_SIMPLE_CLAUSE(Init, OMPC_init) CHECK_SIMPLE_CLAUSE(Use, OMPC_use) @@ -2555,6 +2586,22 @@ CHECK_REQ_CONSTANT_SCALAR_INT_CLAUSE(Simdlen, OMPC_simdlen) // Restrictions specific to each clause are implemented apart from the // generalized restrictions. + +void OmpStructureChecker::Enter(const parser::OmpClause::Destroy &x) { + CheckAllowedClause(llvm::omp::Clause::OMPC_destroy); + + llvm::omp::Directive dir{GetContext().directive}; + unsigned version{context_.langOptions().OpenMPVersion}; + if (dir == llvm::omp::Directive::OMPD_depobj) { + if (version < 52) { + context_.Say(GetContext().clauseSource, + "The object parameter in DESTROY clause in DEPOPJ construct " + "was introduced in %s"_port_en_US, + ThisVersion(52)); + } + } +} + void OmpStructureChecker::Enter(const parser::OmpClause::Reduction &x) { CheckAllowedClause(llvm::omp::Clause::OMPC_reduction); if (CheckReductionOperators(x)) { @@ -3285,16 +3332,63 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Device &x) { void OmpStructureChecker::Enter(const parser::OmpClause::Depend &x) { CheckAllowedClause(llvm::omp::Clause::OMPC_depend); - if ((std::holds_alternative(x.v.u) || - std::holds_alternative(x.v.u)) && - GetContext().directive != llvm::omp::OMPD_ordered) { - context_.Say(GetContext().clauseSource, - "DEPEND(SOURCE) or DEPEND(SINK : vec) can be used only with the ordered" - " directive. Used here in the %s construct."_err_en_US, - parser::ToUpperCaseLetters(getDirectiveName(GetContext().directive))); + llvm::omp::Directive directive{GetContext().directive}; + unsigned version{context_.langOptions().OpenMPVersion}; + + using DepType = parser::OmpTaskDependenceType::Type; + DepType depType = x.v.GetDepType(); + + if (version >= 52) { + switch (depType) { + case DepType::Sink: + case DepType::Source: + context_.Say(GetContext().clauseSource, + "The %s task-dependence-type is deprecated in %s"_warn_en_US, + parser::ToUpperCaseLetters( + parser::OmpTaskDependenceType::EnumToString(depType)), + ThisVersion(version)); + break; + default: + break; + } + } + + if (directive == llvm::omp::OMPD_depobj) { + // [5.0:255:11], [5.1:288:3] + // A depend clause on a depobj construct must not have source, sink [or + // depobj](5.0) as dependence-type. + if (version >= 50) { + bool invalidDep{depType == DepType::Source || depType == DepType::Sink}; + if (version == 50) { + invalidDep = invalidDep || depType == DepType::Depobj; + } + if (invalidDep) { + context_.Say(GetContext().clauseSource, + "A DEPEND clause on a DEPOBJ construct must not have SOURCE%s " + "as dependence-type"_err_en_US, + version == 50 ? ", SINK or DEPOBJ" : " or SINK"); + } + } + } else if (directive != llvm::omp::OMPD_ordered) { + if (depType == DepType::Source || depType == DepType::Sink) { + context_.Say(GetContext().clauseSource, + "DEPEND(SOURCE) or DEPEND(SINK : vec) can be used only with the " + "ordered directive. Used here in the %s construct."_err_en_US, + parser::ToUpperCaseLetters(getDirectiveName(directive))); + } } if (const auto *inOut{std::get_if(&x.v.u)}) { - for (const auto &object : std::get(inOut->t).v) { + auto &objList{std::get(inOut->t)}; + if (directive == llvm::omp::OMPD_depobj) { + // [5.0:255:13], [5.1:288:6], [5.2:322:26] + // A depend clause on a depobj construct must only specify one locator. + if (objList.v.size() != 1) { + context_.Say(GetContext().clauseSource, + "A DEPEND clause on a DEPOBJ construct must only specify " + "one locator"_err_en_US); + } + } + for (const auto &object : objList.v) { if (const auto *name{std::get_if(&object.u)}) { context_.Say(GetContext().clauseSource, "Common block name ('%s') cannot appear in a DEPEND " @@ -3313,12 +3407,18 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Depend &x) { } } if (std::get>(inOut->t)) { - unsigned version{context_.langOptions().OpenMPVersion}; unsigned allowedInVersion{50}; if (version < allowedInVersion) { context_.Say(GetContext().clauseSource, "Iterator modifiers are not supported in %s, %s"_warn_en_US, ThisVersion(version), TryVersion(allowedInVersion)); + } else { + if (directive == llvm::omp::OMPD_depobj) { + context_.Say(GetContext().clauseSource, + "An iterator-modifier may specify multiple locators, " + "a DEPEND clause on a DEPOBJ construct must only specify " + "one locator"_warn_en_US); + } } } } @@ -3433,6 +3533,34 @@ void OmpStructureChecker::CheckStructureElement( return; } +void OmpStructureChecker::Enter(const parser::OmpClause::Update &x) { + CheckAllowedClause(llvm::omp::Clause::OMPC_update); + llvm::omp::Directive directive{GetContext().directive}; + unsigned version{context_.langOptions().OpenMPVersion}; + + // [5.1:288:4-5] + // An update clause on a depobj construct must not have source, sink or depobj + // as dependence-type. + // [5.2:322:3] + // task-dependence-type must not be depobj. + if (directive == llvm::omp::OMPD_depobj) { + if (version >= 51) { + // Update -> OmpUpdateClause -> OmpTaskDependenceType -> Type + switch (x.v.v.v) { + case parser::OmpTaskDependenceType::Type::Source: + case parser::OmpTaskDependenceType::Type::Sink: + case parser::OmpTaskDependenceType::Type::Depobj: + context_.Say(GetContext().clauseSource, + "An UPDATE clause on a DEPOBJ construct must not have SOURCE, " + "SINK or DEPOBJ as dependence-type"_err_en_US); + break; + default: + break; + } + } + } +} + void OmpStructureChecker::Enter(const parser::OmpClause::UseDevicePtr &x) { CheckStructureElement(x.v, llvm::omp::Clause::OMPC_use_device_ptr); CheckAllowedClause(llvm::omp::Clause::OMPC_use_device_ptr); @@ -3616,7 +3744,7 @@ void OmpStructureChecker::CheckDependList(const parser::DataRef &d) { context_.Say(GetContext().clauseSource, "Coarrays are not supported in DEPEND clause"_err_en_US); }, - [&](const parser::Name &) { return; }, + [&](const parser::Name &) {}, }, d.u); } diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h index 237569bc40c48..d5fd558cea237 100644 --- a/flang/lib/Semantics/check-omp-structure.h +++ b/flang/lib/Semantics/check-omp-structure.h @@ -92,6 +92,8 @@ class OmpStructureChecker void Leave(const parser::OpenMPDeclarativeAllocate &); void Enter(const parser::OpenMPDeclareTargetConstruct &); void Leave(const parser::OpenMPDeclareTargetConstruct &); + void Enter(const parser::OpenMPDepobjConstruct &); + void Leave(const parser::OpenMPDepobjConstruct &); void Enter(const parser::OmpDeclareTargetWithList &); void Enter(const parser::OmpDeclareTargetWithClause &); void Leave(const parser::OmpDeclareTargetWithClause &); diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp index 014b7987a658b..d85109fc9cda8 100644 --- a/flang/lib/Semantics/resolve-directives.cpp +++ b/flang/lib/Semantics/resolve-directives.cpp @@ -383,6 +383,14 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor { } void Post(const parser::OpenMPDeclareSimdConstruct &) { PopContext(); } + bool Pre(const parser::OpenMPDepobjConstruct &x) { + PushContext(x.source, llvm::omp::Directive::OMPD_depobj); + auto &object{std::get(x.t)}; + ResolveOmpObject(object, Symbol::Flag::OmpDependObject); + return true; + } + void Post(const parser::OpenMPDepobjConstruct &) { PopContext(); } + bool Pre(const parser::OpenMPRequiresConstruct &x) { using Flags = WithOmpDeclarative::RequiresFlags; using Requires = WithOmpDeclarative::RequiresFlag; diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp index add4e4befd3a2..e0a8246ebc752 100644 --- a/flang/lib/Semantics/resolve-names.cpp +++ b/flang/lib/Semantics/resolve-names.cpp @@ -1538,6 +1538,13 @@ class OmpVisitor : public virtual DeclarationVisitor { void Post(const parser::OpenMPDeclarativeConstruct &) { messageHandler().set_currStmtSource(std::nullopt); } + bool Pre(const parser::OpenMPDepobjConstruct &x) { + AddOmpSourceRange(x.source); + return true; + } + void Post(const parser::OpenMPDepobjConstruct &x) { + messageHandler().set_currStmtSource(std::nullopt); + } bool Pre(const parser::OpenMPAtomicConstruct &x) { return common::visit(common::visitors{[&](const auto &u) -> bool { AddOmpSourceRange(u.source); diff --git a/flang/test/Lower/OpenMP/Todo/depobj-construct.f90 b/flang/test/Lower/OpenMP/Todo/depobj-construct.f90 new file mode 100644 index 0000000000000..2b3c4d92c4a4f --- /dev/null +++ b/flang/test/Lower/OpenMP/Todo/depobj-construct.f90 @@ -0,0 +1,9 @@ +!RUN: %not_todo_cmd bbc -emit-hlfir -fopenmp -fopenmp-version=50 -o - %s 2>&1 | FileCheck %s +!RUN: %not_todo_cmd %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 -o - %s 2>&1 | FileCheck %s + +!CHECK: not yet implemented: OpenMPDepobjConstruct +subroutine f00() + integer :: obj + integer :: x + !$omp depobj(obj) depend(in: x) +end diff --git a/flang/test/Parser/OpenMP/depobj-construct.f90 b/flang/test/Parser/OpenMP/depobj-construct.f90 new file mode 100644 index 0000000000000..7c474071bc1e6 --- /dev/null +++ b/flang/test/Parser/OpenMP/depobj-construct.f90 @@ -0,0 +1,64 @@ +!RUN: %flang_fc1 -fdebug-unparse -fopenmp -fopenmp-version=52 %s | FileCheck --ignore-case --check-prefix="UNPARSE" %s +!RUN: %flang_fc1 -fdebug-dump-parse-tree -fopenmp -fopenmp-version=52 %s | FileCheck --check-prefix="PARSE-TREE" %s + +subroutine f00 + integer :: x, y + !$omp depobj(x) depend(in: y) +end + +!UNPARSE: SUBROUTINE f00 +!UNPARSE: INTEGER x, y +!UNPARSE: !$OMP DEPOBJ(x) DEPEND(IN:y) +!UNPARSE: END SUBROUTINE + +!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPStandaloneConstruct -> OpenMPDepobjConstruct +!PARSE-TREE: | Verbatim +!PARSE-TREE: | OmpObject -> Designator -> DataRef -> Name = 'x' +!PARSE-TREE: | OmpClause -> Depend -> OmpDependClause -> InOut +!PARSE-TREE: | | OmpTaskDependenceType -> Type = In +!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'y' + +subroutine f01 + integer :: x + !$omp depobj(x) update(out) +end + +!UNPARSE: SUBROUTINE f01 +!UNPARSE: INTEGER x +!UNPARSE: !$OMP DEPOBJ(x) UPDATE(OUT) +!UNPARSE: END SUBROUTINE + +!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPStandaloneConstruct -> OpenMPDepobjConstruct +!PARSE-TREE: | Verbatim +!PARSE-TREE: | OmpObject -> Designator -> DataRef -> Name = 'x' +!PARSE-TREE: | OmpClause -> Update -> OmpUpdateClause -> OmpTaskDependenceType -> Type = Out + +subroutine f02 + integer :: x + !$omp depobj(x) destroy(x) +end + +!UNPARSE: SUBROUTINE f02 +!UNPARSE: INTEGER x +!UNPARSE: !$OMP DEPOBJ(x) DESTROY(x) +!UNPARSE: END SUBROUTINE + +!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPStandaloneConstruct -> OpenMPDepobjConstruct +!PARSE-TREE: | Verbatim +!PARSE-TREE: | OmpObject -> Designator -> DataRef -> Name = 'x' +!PARSE-TREE: | OmpClause -> Destroy -> OmpDestroyClause -> OmpObject -> Designator -> DataRef -> Name = 'x' + +subroutine f03 + integer :: x + !$omp depobj(x) destroy +end + +!UNPARSE: SUBROUTINE f03 +!UNPARSE: INTEGER x +!UNPARSE: !$OMP DEPOBJ(x) DESTROY +!UNPARSE: END SUBROUTINE + +!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPStandaloneConstruct -> OpenMPDepobjConstruct +!PARSE-TREE: | Verbatim +!PARSE-TREE: | OmpObject -> Designator -> DataRef -> Name = 'x' +!PARSE-TREE: | OmpClause -> Destroy -> diff --git a/flang/test/Semantics/OpenMP/depobj-construct-v50.f90 b/flang/test/Semantics/OpenMP/depobj-construct-v50.f90 new file mode 100644 index 0000000000000..e7fa24d521b63 --- /dev/null +++ b/flang/test/Semantics/OpenMP/depobj-construct-v50.f90 @@ -0,0 +1,28 @@ +!RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=50 + +subroutine f00 + integer :: obj +!ERROR: A DEPEND clause on a DEPOBJ construct must not have SOURCE, SINK or DEPOBJ as dependence-type + !$omp depobj(obj) depend(source) +end + +subroutine f01 + integer :: obj + integer :: x, y +!ERROR: A DEPEND clause on a DEPOBJ construct must only specify one locator + !$omp depobj(obj) depend(in: x, y) +end + +subroutine f02 + integer :: obj + integer :: x(10) +!WARNING: An iterator-modifier may specify multiple locators, a DEPEND clause on a DEPOBJ construct must only specify one locator + !$omp depobj(obj) depend(iterator(i = 1:10), in: x(i)) +end + +subroutine f03 + integer :: obj, jbo +!ERROR: The DESTROY clause must refer to the same object as the DEPOBJ construct +!PORTABILITY: The object parameter in DESTROY clause in DEPOPJ construct was introduced in OpenMP v5.2 + !$omp depobj(obj) destroy(jbo) +end diff --git a/flang/test/Semantics/OpenMP/depobj-construct-v51.f90 b/flang/test/Semantics/OpenMP/depobj-construct-v51.f90 new file mode 100644 index 0000000000000..fa0c025a11010 --- /dev/null +++ b/flang/test/Semantics/OpenMP/depobj-construct-v51.f90 @@ -0,0 +1,13 @@ +!RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=51 + +subroutine f04 + integer :: obj +!ERROR: An UPDATE clause on a DEPOBJ construct must not have SOURCE, SINK or DEPOBJ as dependence-type + !$omp depobj(obj) update(source) +end + +subroutine f05 + integer :: obj +!ERROR: An UPDATE clause on a DEPOBJ construct must not have SOURCE, SINK or DEPOBJ as dependence-type + !$omp depobj(obj) update(depobj) +end diff --git a/flang/test/Semantics/OpenMP/depobj-construct-v52.f90 b/flang/test/Semantics/OpenMP/depobj-construct-v52.f90 new file mode 100644 index 0000000000000..f2e66485c6c80 --- /dev/null +++ b/flang/test/Semantics/OpenMP/depobj-construct-v52.f90 @@ -0,0 +1,15 @@ +!RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=52 + +subroutine f00 + integer :: obj +!WARNING: The SOURCE task-dependence-type is deprecated in OpenMP v5.2 +!ERROR: A DEPEND clause on a DEPOBJ construct must not have SOURCE or SINK as dependence-type + !$omp depobj(obj) depend(source) +end + +subroutine f03 + integer :: obj, jbo +!Note: no portability message +!ERROR: The DESTROY clause must refer to the same object as the DEPOBJ construct + !$omp depobj(obj) destroy(jbo) +end diff --git a/llvm/include/llvm/Frontend/OpenMP/ClauseT.h b/llvm/include/llvm/Frontend/OpenMP/ClauseT.h index 2a890905dc632..8ff15b51f1abd 100644 --- a/llvm/include/llvm/Frontend/OpenMP/ClauseT.h +++ b/llvm/include/llvm/Frontend/OpenMP/ClauseT.h @@ -239,7 +239,8 @@ struct MapperT { ENUM(MemoryOrder, AcqRel, Acquire, Relaxed, Release, SeqCst); ENUM(MotionExpectation, Present); // V5.2: [15.9.1] `task-dependence-type` modifier -ENUM(TaskDependenceType, In, Out, Inout, Mutexinoutset, Inoutset, Depobj); +ENUM(TaskDependenceType, Depobj, In, Inout, Inoutset, Mutexinoutset, Out, Sink, + Source); template // struct LoopIterationT { diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td index 70179bab47577..97496d4aae5ae 100644 --- a/llvm/include/llvm/Frontend/OpenMP/OMP.td +++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td @@ -130,6 +130,8 @@ def OMPC_Depobj : Clause<"depobj"> { } def OMPC_Destroy : Clause<"destroy"> { let clangClass = "OMPDestroyClause"; + let flangClass = "OmpDestroyClause"; + let isValueOptional = true; } def OMPC_Detach : Clause<"detach"> { let clangClass = "OMPDetachClause"; @@ -481,6 +483,7 @@ def OMPC_Untied : Clause<"untied"> { } def OMPC_Update : Clause<"update"> { let clangClass = "OMPUpdateClause"; + let flangClass = "OmpUpdateClause"; } def OMPC_Use : Clause<"use"> { let clangClass = "OMPUseClause";