diff --git a/flang/docs/OpenMP-semantics.md b/flang/docs/OpenMP-semantics.md --- a/flang/docs/OpenMP-semantics.md +++ b/flang/docs/OpenMP-semantics.md @@ -48,6 +48,7 @@ * declare target * threadprivate * declare reduction +* requires There is a parser node for each of these directives and the parser node saves information associated with the directive, 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 @@ -562,9 +562,12 @@ NODE(parser, OmpMemoryOrderClause) NODE(parser, OmpAtomicClause) NODE(parser, OmpAtomicClauseList) + NODE(parser, OmpAtomicDefaultMemOrderClause) + NODE_ENUM(OmpAtomicDefaultMemOrderClause, Type) NODE(parser, OpenMPFlushConstruct) NODE(parser, OpenMPLoopConstruct) NODE(parser, OpenMPExecutableAllocate) + NODE(parser, OpenMPRequiresConstruct) NODE(parser, OpenMPSimpleStandaloneConstruct) NODE(parser, OpenMPStandaloneConstruct) NODE(parser, OpenMPSectionConstruct) 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 @@ -3494,6 +3494,14 @@ std::variant u; }; +// OMP 5.0 2.4 atomic-default-mem-order-clause -> +// ATOMIC_DEFAULT_MEM_ORDER (SEQ_CST | ACQ_REL | +// RELAXED) +struct OmpAtomicDefaultMemOrderClause { + ENUM_CLASS(Type, SeqCst, AcqRel, Relaxed) + WRAPPER_CLASS_BOILERPLATE(OmpAtomicDefaultMemOrderClause, Type); +}; + // OpenMP Clauses struct OmpClause { UNION_CLASS_BOILERPLATE(OmpClause); @@ -3611,6 +3619,13 @@ std::tuple, OmpClauseList> t; }; +// 2.4 requires -> REQUIRES requires-clause[ [ [,] requires-clause]...] +struct OpenMPRequiresConstruct { + TUPLE_CLASS_BOILERPLATE(OpenMPRequiresConstruct); + CharBlock source; + std::tuple t; +}; + // 2.15.2 threadprivate -> THREADPRIVATE (variable-name-list) struct OpenMPThreadprivate { TUPLE_CLASS_BOILERPLATE(OpenMPThreadprivate); @@ -3630,7 +3645,7 @@ CharBlock source; std::variant + OpenMPThreadprivate, OpenMPRequiresConstruct> u; }; diff --git a/flang/lib/Lower/OpenMP.cpp b/flang/lib/Lower/OpenMP.cpp --- a/flang/lib/Lower/OpenMP.cpp +++ b/flang/lib/Lower/OpenMP.cpp @@ -1815,6 +1815,10 @@ TODO(converter.getCurrentLocation(), "OpenMPDeclareTargetConstruct"); }, + [&](const Fortran::parser::OpenMPRequiresConstruct + &requiresConstruct) { + TODO(converter.getCurrentLocation(), "OpenMPRequiresConstruct"); + }, [&](const Fortran::parser::OpenMPThreadprivate &threadprivate) { // The directive is lowered when instantiating the variable to // support the case of threadprivate variable declared in module. 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 @@ -191,6 +191,9 @@ parenthesized(Parser{}))) || "ALLOCATOR" >> construct(construct( parenthesized(scalarIntExpr))) || + "ATOMIC_DEFAULT_MEM_ORDER" >> + construct(construct( + parenthesized(Parser{}))) || "COLLAPSE" >> construct(construct( parenthesized(scalarIntConstantExpr))) || "COPYIN" >> construct(construct( @@ -208,6 +211,8 @@ "DIST_SCHEDULE" >> construct(construct( parenthesized("STATIC" >> maybe("," >> scalarIntExpr)))) || + "DYNAMIC_ALLOCATORS" >> + construct(construct()) || "FINAL" >> construct(construct( parenthesized(scalarLogicalExpr))) || "FIRSTPRIVATE" >> construct(construct( @@ -261,6 +266,8 @@ parenthesized(Parser{}))) || "RELAXED" >> construct(construct()) || "RELEASE" >> construct(construct()) || + "REVERSE_OFFLOAD" >> + construct(construct()) || "SAFELEN" >> construct(construct( parenthesized(scalarIntConstantExpr))) || "SCHEDULE" >> construct(construct( @@ -278,6 +285,10 @@ parenthesized(Parser{}))) || "USE_DEVICE_PTR" >> construct(construct( parenthesized(nonemptyList(name)))) || + "UNIFIED_ADDRESS" >> + construct(construct()) || + "UNIFIED_SHARED_MEMORY" >> + construct(construct()) || "UNIFORM" >> construct(construct( parenthesized(nonemptyList(name)))) || "UNTIED" >> construct(construct())) @@ -357,6 +368,16 @@ "ACQUIRE" >> construct(construct()) || "RELAXED" >> construct(construct()))))) +// 2.4 Requires construct [OpenMP 5.0] +// atomic-default-mem-order-clause -> +// seq_cst +// acq_rel +// relaxed +TYPE_PARSER(construct( + "SEQ_CST" >> pure(OmpAtomicDefaultMemOrderClause::Type::SeqCst) || + "ACQ_REL" >> pure(OmpAtomicDefaultMemOrderClause::Type::AcqRel) || + "RELAXED" >> pure(OmpAtomicDefaultMemOrderClause::Type::Relaxed))) + // 2.17.7 Atomic construct // atomic-clause -> memory-order-clause | HINT(hint-expression) TYPE_PARSER(sourced(construct( @@ -519,6 +540,10 @@ sourced(construct(verbatim("DECLARE SIMD"_tok), maybe(parenthesized(name)), Parser{}))) +// 2.4 Requires construct +TYPE_PARSER(sourced(construct( + verbatim("REQUIRES"_tok), some(Parser{} / maybe(","_tok))))) + // 2.15.2 Threadprivate directive TYPE_PARSER(sourced(construct( verbatim("THREADPRIVATE"_tok), parenthesized(Parser{})))) @@ -539,6 +564,8 @@ Parser{}) || construct( Parser{}) || + construct( + Parser{}) || construct(Parser{})) / endOmpLine) 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 @@ -2229,6 +2229,21 @@ break; } } + + void Unparse(const OmpAtomicDefaultMemOrderClause &x) { + switch (x.v) { + case OmpAtomicDefaultMemOrderClause::Type::SeqCst: + Word("SEQ_CST"); + break; + case OmpAtomicDefaultMemOrderClause::Type::AcqRel: + Word("ACQ_REL"); + break; + case OmpAtomicDefaultMemOrderClause::Type::Relaxed: + Word("RELAXED"); + break; + } + } + void Unparse(const OmpAtomicClauseList &x) { Walk(" ", x.v, " "); } void Unparse(const OmpAtomic &x) { @@ -2393,6 +2408,13 @@ Word("DECLARE TARGET "); return true; }, + [&](const OpenMPRequiresConstruct &y) { + Word("REQUIRES "); + Walk(std::get(y.t)); + Put("\n"); + EndOpenMP(); + return false; + }, [&](const OpenMPThreadprivate &) { Word("THREADPRIVATE ("); return true; diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h --- a/flang/lib/Semantics/check-omp-structure.h +++ b/flang/lib/Semantics/check-omp-structure.h @@ -152,6 +152,8 @@ void Leave(const parser::OpenMPDeclareTargetConstruct &); void Enter(const parser::OpenMPExecutableAllocate &); void Leave(const parser::OpenMPExecutableAllocate &); + void Enter(const parser::OpenMPRequiresConstruct &); + void Leave(const parser::OpenMPRequiresConstruct &); void Enter(const parser::OpenMPThreadprivate &); void Leave(const parser::OpenMPThreadprivate &); 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 @@ -1060,6 +1060,15 @@ 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); +} + +void OmpStructureChecker::Leave(const parser::OpenMPRequiresConstruct &) { + dirContext_.pop_back(); +} + void OmpStructureChecker::Enter(const parser::OpenMPDeclarativeAllocate &x) { isPredefinedAllocator = true; const auto &dir{std::get(x.t)}; diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp --- a/flang/lib/Semantics/resolve-directives.cpp +++ b/flang/lib/Semantics/resolve-directives.cpp @@ -323,6 +323,13 @@ return true; } void Post(const parser::OpenMPDeclareSimdConstruct &) { PopContext(); } + + bool Pre(const parser::OpenMPRequiresConstruct &x) { + PushContext(x.source, llvm::omp::Directive::OMPD_requires); + return true; + } + void Post(const parser::OpenMPRequiresConstruct &) { PopContext(); } + bool Pre(const parser::OpenMPThreadprivate &); void Post(const parser::OpenMPThreadprivate &) { PopContext(); } diff --git a/flang/test/Semantics/OpenMP/omp-declarative-directive.f90 b/flang/test/Semantics/OpenMP/omp-declarative-directive.f90 --- a/flang/test/Semantics/OpenMP/omp-declarative-directive.f90 +++ b/flang/test/Semantics/OpenMP/omp-declarative-directive.f90 @@ -5,6 +5,20 @@ !TODO: all internal errors ! enable declare-reduction example after name resolution +! 2.4 requires + +subroutine requires_1(a) + real(8), intent(inout) :: a + !$omp requires reverse_offload, unified_shared_memory, atomic_default_mem_order(relaxed) + a = a + 0.01 +end subroutine requires_1 + +subroutine requires_2(a) + real(8), intent(inout) :: a + !$omp requires unified_address + a = a + 0.01 +end subroutine requires_2 + ! 2.8.2 declare-simd subroutine declare_simd_1(a, b) diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td --- a/llvm/include/llvm/Frontend/OpenMP/OMP.td +++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td @@ -299,6 +299,7 @@ } def OMPC_AtomicDefaultMemOrder : Clause<"atomic_default_mem_order"> { let clangClass = "OMPAtomicDefaultMemOrderClause"; + let flangClass = "OmpAtomicDefaultMemOrderClause"; } def OMPC_Allocate : Clause<"allocate"> { let clangClass = "OMPAllocateClause"; @@ -614,7 +615,7 @@ ]; } def OMP_Requires : Directive<"requires"> { - let allowedClauses = [ + let allowedOnceClauses = [ VersionedClause, VersionedClause, // OpenMP 5.2 Spec: If an implementation is not supporting a requirement