diff --git a/flang/include/flang/Common/Fortran-features.h b/flang/include/flang/Common/Fortran-features.h --- a/flang/include/flang/Common/Fortran-features.h +++ b/flang/include/flang/Common/Fortran-features.h @@ -24,7 +24,7 @@ OldStyleParameter, ComplexConstructor, PercentLOC, SignedPrimary, FileName, Convert, Dispose, IOListLeadingComma, AbbreviatedEditDescriptor, ProgramParentheses, PercentRefAndVal, OmitFunctionDummies, CrayPointer, - Hollerith, ArithmeticIF, Assign, AssignedGOTO, Pause, OpenMP, + Hollerith, ArithmeticIF, Assign, AssignedGOTO, Pause, OpenACC, OpenMP, CruftAfterAmpersand, ClassicCComments, AdditionalFormats, BigIntLiterals, RealDoControls, EquivalenceNumericWithCharacter, AdditionalIntrinsics, AnonymousParents, OldLabelDoEndStatements, LogicalIntegerAssignment, @@ -37,6 +37,7 @@ LanguageFeatureControl() { // These features must be explicitly enabled by command line options. disable_.set(LanguageFeature::OldDebugLines); + disable_.set(LanguageFeature::OpenACC); disable_.set(LanguageFeature::OpenMP); // These features, if enabled, conflict with valid standard usage, // so there are disabled here by default. @@ -50,7 +51,9 @@ void WarnOnAllNonstandard(bool yes = true) { warnAll_ = yes; } bool IsEnabled(LanguageFeature f) const { return !disable_.test(f); } bool ShouldWarn(LanguageFeature f) const { - return (warnAll_ && f != LanguageFeature::OpenMP) || warn_.test(f); + return (warnAll_ && f != LanguageFeature::OpenMP && + f != LanguageFeature::OpenACC) || + warn_.test(f); } // Return all spellings of operators names, depending on features enabled std::vector GetNames(LogicalOperator) const; 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 @@ -53,6 +53,88 @@ NODE(format, IntrinsicTypeDataEditDesc) NODE(format::IntrinsicTypeDataEditDesc, Kind) NODE(parser, Abstract) + NODE(parser, AccAtomicCapture) + NODE(AccAtomicCapture, Stmt1) + NODE(AccAtomicCapture, Stmt2) + NODE(parser, AccAtomicRead) + NODE(parser, AccAtomicUpdate) + NODE(parser, AccAtomicWrite) + NODE(parser, AccBeginBlockDirective) + NODE(parser, AccBeginCombinedDirective) + NODE(parser, AccBeginLoopDirective) + NODE(parser, AccBlockDirective) + NODE(parser, AccClause) + NODE(AccClause, Auto) + NODE(AccClause, Async) + NODE(AccClause, Attach) + NODE(AccClause, Bind) + NODE(AccClause, Capture) + NODE(AccClause, Collapse) + NODE(AccClause, Copy) + NODE(AccClause, Copyin) + NODE(AccClause, Copyout) + NODE(AccClause, Create) + NODE(AccClause, Default) + NODE(AccClause, DefaultAsync) + NODE(AccClause, Delete) + NODE(AccClause, Detach) + NODE(AccClause, Device) + NODE(AccClause, DeviceNum) + NODE(AccClause, DevicePtr) + NODE(AccClause, DeviceResident) + NODE(AccClause, DeviceType) + NODE(AccClause, Finalize) + NODE(AccClause, FirstPrivate) + NODE(AccClause, Gang) + NODE(AccClause, Host) + NODE(AccClause, If) + NODE(AccClause, IfPresent) + NODE(AccClause, Independent) + NODE(AccClause, Link) + NODE(AccClause, NoCreate) + NODE(AccClause, NoHost) + NODE(AccClause, NumGangs) + NODE(AccClause, NumWorkers) + NODE(AccClause, Present) + NODE(AccClause, Private) + NODE(AccClause, Tile) + NODE(AccClause, UseDevice) + NODE(AccClause, Read) + NODE(AccClause, Reduction) + NODE(AccClause, Self) + NODE(AccClause, Seq) + NODE(AccClause, Vector) + NODE(AccClause, VectorLength) + NODE(AccClause, Wait) + NODE(AccClause, Worker) + NODE(AccClause, Write) + NODE(AccClause, Unknown) + NODE(parser, AccDefaultClause) + NODE_ENUM(parser::AccDefaultClause, Arg) + NODE(parser, AccClauseList) + NODE(parser, AccCombinedDirective) + NODE(parser, AccDataModifier) + NODE_ENUM(parser::AccDataModifier, Modifier) + NODE(parser, AccDeclarativeDirective) + NODE(parser, AccEndAtomic) + NODE(parser, AccEndBlockDirective) + NODE(parser, AccEndCombinedDirective) + NODE(parser, AccGangArgument) + NODE(parser, AccObject) + NODE(parser, AccObjectList) + NODE(parser, AccObjectListWithModifier) + NODE(parser, AccObjectListWithReduction) + NODE(parser, AccReductionOperator) + NODE(parser, AccSizeExpr) + NODE(parser, AccSizeExprList) + NODE(parser, AccStandaloneDirective) + NODE(parser, AccLoopDirective) + NODE(parser, AccWaitArgument) + static std::string GetNodeName(const llvm::acc::Directive &x) { + return llvm::Twine( + "llvm::acc::Directive = ", llvm::acc::getOpenACCDirectiveName(x)) + .str(); + } NODE(parser, AcImpliedDo) NODE(parser, AcImpliedDoControl) NODE(parser, AcValue) @@ -510,6 +592,17 @@ NODE(parser, OmpSectionsDirective) NODE(parser, OmpSimpleStandaloneDirective) NODE(parser, Only) + NODE(parser, OpenACCAtomicConstruct) + NODE(parser, OpenACCBlockConstruct) + NODE(parser, OpenACCCacheConstruct) + NODE(parser, OpenACCCombinedConstruct) + NODE(parser, OpenACCConstruct) + NODE(parser, OpenACCDeclarativeConstruct) + NODE(parser, OpenACCLoopConstruct) + NODE(parser, OpenACCRoutineConstruct) + NODE(parser, OpenACCStandaloneDeclarativeConstruct) + NODE(parser, OpenACCStandaloneConstruct) + NODE(parser, OpenACCWaitConstruct) NODE(parser, OpenMPAtomicConstruct) NODE(parser, OpenMPBlockConstruct) NODE(parser, OpenMPCancelConstruct) 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 @@ -25,6 +25,7 @@ #include "flang/Common/Fortran.h" #include "flang/Common/idioms.h" #include "flang/Common/indirection.h" +#include "llvm/Frontend/OpenACC/ACC.h.inc" #include "llvm/Frontend/OpenMP/OMPConstants.h" #include #include @@ -256,6 +257,8 @@ struct AssignStmt; struct AssignedGotoStmt; struct PauseStmt; +struct OpenACCConstruct; +struct OpenACCDeclarativeConstruct; struct OpenMPConstruct; struct OpenMPDeclarativeConstruct; struct OmpEndLoopDirective; @@ -386,6 +389,7 @@ Statement, Statement>, common::Indirection, + common::Indirection, common::Indirection, common::Indirection> u; @@ -424,7 +428,8 @@ // from the implicit part to the declaration constructs struct SpecificationPart { TUPLE_CLASS_BOILERPLATE(SpecificationPart); - std::tuple, + std::tuple, + std::list, std::list>>, std::list>>, ImplicitPart, std::list> @@ -509,6 +514,7 @@ common::Indirection, common::Indirection, common::Indirection, common::Indirection, + common::Indirection, common::Indirection, common::Indirection> u; @@ -3789,5 +3795,287 @@ OpenMPCriticalConstruct> u; }; + +// Parse tree nodes for OpenACC 3.0 directives and clauses + +struct AccObject { + UNION_CLASS_BOILERPLATE(AccObject); + std::variant u; +}; + +WRAPPER_CLASS(AccObjectList, std::list); + +// OpenACC directive beginning or ending a block +struct AccBlockDirective { + WRAPPER_CLASS_BOILERPLATE(AccBlockDirective, llvm::acc::Directive); + CharBlock source; +}; + +struct AccLoopDirective { + WRAPPER_CLASS_BOILERPLATE(AccLoopDirective, llvm::acc::Directive); + CharBlock source; +}; + +struct AccStandaloneDirective { + WRAPPER_CLASS_BOILERPLATE(AccStandaloneDirective, llvm::acc::Directive); + CharBlock source; +}; + +// 2.11 Combined constructs +struct AccCombinedDirective { + WRAPPER_CLASS_BOILERPLATE(AccCombinedDirective, llvm::acc::Directive); + CharBlock source; +}; + +struct AccDeclarativeDirective { + WRAPPER_CLASS_BOILERPLATE(AccDeclarativeDirective, llvm::acc::Directive); + CharBlock source; +}; + +// OpenACC Clauses +struct AccDefaultClause { + ENUM_CLASS(Arg, None, Present) + WRAPPER_CLASS_BOILERPLATE(AccDefaultClause, Arg); + CharBlock source; +}; + +struct AccDataModifier { + ENUM_CLASS(Modifier, ReadOnly, Zero) + WRAPPER_CLASS_BOILERPLATE(AccDataModifier, Modifier); + CharBlock source; +}; + +struct AccObjectListWithModifier { + TUPLE_CLASS_BOILERPLATE(AccObjectListWithModifier); + std::tuple, AccObjectList> t; +}; + +// 2.5.13: + | * | max | min | iand | ior | ieor | .and. | .or. | .eqv. | .neqv. +struct AccReductionOperator { + UNION_CLASS_BOILERPLATE(AccReductionOperator); + std::variant u; +}; + +struct AccObjectListWithReduction { + TUPLE_CLASS_BOILERPLATE(AccObjectListWithReduction); + std::tuple t; +}; + +struct AccWaitArgument { + TUPLE_CLASS_BOILERPLATE(AccWaitArgument); + std::tuple, std::list> t; +}; + +struct AccSizeExpr { + TUPLE_CLASS_BOILERPLATE(AccSizeExpr); + CharBlock source; + std::tuple> t; // if null then * +}; + +struct AccSizeExprList { + WRAPPER_CLASS_BOILERPLATE(AccSizeExprList, std::list); +}; + +struct AccGangArgument { + TUPLE_CLASS_BOILERPLATE(AccGangArgument); + std::tuple, std::optional> t; +}; + +struct AccClause { + UNION_CLASS_BOILERPLATE(AccClause); + + EMPTY_CLASS(Auto); + WRAPPER_CLASS(Async, std::optional); + WRAPPER_CLASS(Attach, AccObjectList); + WRAPPER_CLASS(Bind, Name); + EMPTY_CLASS(Capture); + WRAPPER_CLASS(Collapse, ScalarIntConstantExpr); + WRAPPER_CLASS(Copy, AccObjectList); + WRAPPER_CLASS(Copyin, AccObjectListWithModifier); + WRAPPER_CLASS(Copyout, AccObjectListWithModifier); + WRAPPER_CLASS(Create, AccObjectListWithModifier); + WRAPPER_CLASS(Default, AccDefaultClause); + WRAPPER_CLASS(DefaultAsync, ScalarIntExpr); + WRAPPER_CLASS(Delete, AccObjectList); + WRAPPER_CLASS(Detach, AccObjectList); + WRAPPER_CLASS(Device, AccObjectList); + WRAPPER_CLASS(DeviceNum, ScalarIntConstantExpr); + WRAPPER_CLASS(DevicePtr, AccObjectList); + WRAPPER_CLASS(DeviceResident, AccObjectList); + WRAPPER_CLASS(DeviceType, std::optional>); + EMPTY_CLASS(Finalize); + WRAPPER_CLASS(FirstPrivate, AccObjectList); + WRAPPER_CLASS(Gang, std::optional); + WRAPPER_CLASS(Host, AccObjectList); + WRAPPER_CLASS(If, ScalarLogicalExpr); + EMPTY_CLASS(IfPresent); + EMPTY_CLASS(Independent); + WRAPPER_CLASS(Link, AccObjectList); + WRAPPER_CLASS(NoCreate, AccObjectList); + EMPTY_CLASS(NoHost); + WRAPPER_CLASS(NumGangs, ScalarIntExpr); + WRAPPER_CLASS(NumWorkers, ScalarIntExpr); + WRAPPER_CLASS(Present, AccObjectList); + WRAPPER_CLASS(Private, AccObjectList); + WRAPPER_CLASS(Tile, AccSizeExprList); + WRAPPER_CLASS(UseDevice, AccObjectList); + EMPTY_CLASS(Read); + WRAPPER_CLASS(Reduction, AccObjectListWithReduction); + WRAPPER_CLASS(Self, std::optional); + EMPTY_CLASS(Seq); + WRAPPER_CLASS(Vector, std::optional); + WRAPPER_CLASS(VectorLength, ScalarIntExpr); + WRAPPER_CLASS(Wait, std::optional); + WRAPPER_CLASS(Worker, std::optional); + EMPTY_CLASS(Write); + EMPTY_CLASS(Unknown); + + CharBlock source; + + std::variant + u; +}; + +struct AccClauseList { + WRAPPER_CLASS_BOILERPLATE(AccClauseList, std::list); + CharBlock source; +}; + +struct OpenACCRoutineConstruct { + TUPLE_CLASS_BOILERPLATE(OpenACCRoutineConstruct); + CharBlock source; + std::tuple, AccClauseList> t; +}; + +struct OpenACCCacheConstruct { + TUPLE_CLASS_BOILERPLATE(OpenACCCacheConstruct); + CharBlock source; + std::tuple t; +}; + +struct OpenACCWaitConstruct { + TUPLE_CLASS_BOILERPLATE(OpenACCWaitConstruct); + CharBlock source; + std::tuple, AccClauseList> t; +}; + +struct AccBeginLoopDirective { + TUPLE_CLASS_BOILERPLATE(AccBeginLoopDirective); + std::tuple t; + CharBlock source; +}; + +struct AccBeginBlockDirective { + TUPLE_CLASS_BOILERPLATE(AccBeginBlockDirective); + CharBlock source; + std::tuple t; +}; + +struct AccEndBlockDirective { + CharBlock source; + WRAPPER_CLASS_BOILERPLATE(AccEndBlockDirective, AccBlockDirective); +}; + +// ACC END ATOMIC +EMPTY_CLASS(AccEndAtomic); + +// ACC ATOMIC READ +struct AccAtomicRead { + TUPLE_CLASS_BOILERPLATE(AccAtomicRead); + std::tuple, std::optional> + t; +}; + +// ACC ATOMIC WRITE +struct AccAtomicWrite { + TUPLE_CLASS_BOILERPLATE(AccAtomicWrite); + std::tuple, std::optional> + t; +}; + +// ACC ATOMIC UPDATE +struct AccAtomicUpdate { + TUPLE_CLASS_BOILERPLATE(AccAtomicUpdate); + std::tuple, Statement, + std::optional> + t; +}; + +// ACC ATOMIC CAPTURE +struct AccAtomicCapture { + TUPLE_CLASS_BOILERPLATE(AccAtomicCapture); + WRAPPER_CLASS(Stmt1, Statement); + WRAPPER_CLASS(Stmt2, Statement); + std::tuple t; +}; + +struct OpenACCAtomicConstruct { + UNION_CLASS_BOILERPLATE(OpenACCAtomicConstruct); + std::variant + u; +}; + +struct OpenACCBlockConstruct { + TUPLE_CLASS_BOILERPLATE(OpenACCBlockConstruct); + std::tuple t; +}; + +struct OpenACCStandaloneDeclarativeConstruct { + TUPLE_CLASS_BOILERPLATE(OpenACCStandaloneDeclarativeConstruct); + CharBlock source; + std::tuple t; +}; + +struct AccBeginCombinedDirective { + TUPLE_CLASS_BOILERPLATE(AccBeginCombinedDirective); + std::tuple t; +}; + +struct AccEndCombinedDirective { + WRAPPER_CLASS_BOILERPLATE(AccEndCombinedDirective, AccCombinedDirective); + CharBlock source; +}; + +struct OpenACCCombinedConstruct { + TUPLE_CLASS_BOILERPLATE(OpenACCCombinedConstruct); + CharBlock source; + std::tuple> + t; +}; + +struct OpenACCDeclarativeConstruct { + UNION_CLASS_BOILERPLATE(OpenACCDeclarativeConstruct); + CharBlock source; + std::variant u; +}; + +// OpenACC directives enclosing do loop +struct OpenACCLoopConstruct { + TUPLE_CLASS_BOILERPLATE(OpenACCLoopConstruct); + OpenACCLoopConstruct(AccBeginLoopDirective &&a) + : t({std::move(a), std::nullopt}) {} + std::tuple> t; +}; + +struct OpenACCStandaloneConstruct { + TUPLE_CLASS_BOILERPLATE(OpenACCStandaloneConstruct); + CharBlock source; + std::tuple t; +}; + +struct OpenACCConstruct { + UNION_CLASS_BOILERPLATE(OpenACCConstruct); + std::variant + u; +}; + } // namespace Fortran::parser #endif // FORTRAN_PARSER_PARSE_TREE_H_ diff --git a/flang/lib/Parser/CMakeLists.txt b/flang/lib/Parser/CMakeLists.txt --- a/flang/lib/Parser/CMakeLists.txt +++ b/flang/lib/Parser/CMakeLists.txt @@ -11,6 +11,7 @@ instrumented-parser.cpp io-parsers.cpp message.cpp + openacc-parsers.cpp openmp-parsers.cpp parse-tree.cpp parsing.cpp @@ -32,4 +33,5 @@ DEPENDS omp_gen + acc_gen ) diff --git a/flang/lib/Parser/executable-parsers.cpp b/flang/lib/Parser/executable-parsers.cpp --- a/flang/lib/Parser/executable-parsers.cpp +++ b/flang/lib/Parser/executable-parsers.cpp @@ -50,6 +50,7 @@ construct(indirect(whereConstruct)), construct(indirect(forallConstruct)), construct(indirect(ompEndLoopDirective)), + construct(indirect(openaccConstruct)), construct(indirect(openmpConstruct)), construct(indirect(compilerDirective)))}; diff --git a/flang/lib/Parser/openacc-parsers.cpp b/flang/lib/Parser/openacc-parsers.cpp new file mode 100644 --- /dev/null +++ b/flang/lib/Parser/openacc-parsers.cpp @@ -0,0 +1,284 @@ +//===-- lib/Parser/openacc-parsers.cpp ------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// Top-level grammar specification for OpenACC 3.0. + +#include "basic-parsers.h" +#include "expr-parsers.h" +#include "misc-parsers.h" +#include "stmt-parser.h" +#include "token-parsers.h" +#include "type-parser-implementation.h" +#include "flang/Parser/parse-tree.h" + +// OpenACC Directives and Clauses +namespace Fortran::parser { + +constexpr auto startAccLine = skipStuffBeforeStatement >> "!$ACC "_sptok; +constexpr auto endAccLine = space >> endOfLine; + +// Basic clauses +TYPE_PARSER("AUTO" >> construct(construct()) || + "ASYNC" >> construct(construct( + maybe(parenthesized(scalarIntExpr)))) || + "ATTACH" >> construct(construct( + parenthesized(Parser{}))) || + "BIND" >> + construct(construct(parenthesized(name))) || + "CAPTURE" >> construct(construct()) || + "COLLAPSE" >> construct(construct( + parenthesized(scalarIntConstantExpr))) || + ("COPY"_tok || "PRESENT_OR_COPY"_tok || "PCOPY"_tok) >> + construct(construct( + parenthesized(Parser{}))) || + ("COPYIN"_tok || "PRESENT_OR_COPYIN"_tok || "PCOPYIN"_tok) >> + construct(construct( + parenthesized(Parser{}))) || + ("COPYOUT"_tok || "PRESENT_OR_COPYOUT"_tok || "PCOPYOUT"_tok) >> + construct(construct( + parenthesized(Parser{}))) || + ("CREATE"_tok || "PRESENT_OR_CREATE"_tok || "PCREATE"_tok) >> + construct(construct( + parenthesized(Parser{}))) || + "DEFAULT" >> construct(construct( + Parser{})) || + "DEFAULT_ASYNC" >> construct(construct( + parenthesized(scalarIntExpr))) || + "DELETE" >> construct(construct( + parenthesized(Parser{}))) || + "DETACH" >> construct(construct( + parenthesized(Parser{}))) || + "DEVICE" >> construct(construct( + parenthesized(Parser{}))) || + "DEVICEPTR" >> construct(construct( + parenthesized(Parser{}))) || + "DEVICENUM" >> construct(construct( + parenthesized(scalarIntConstantExpr))) || + "DEVICE_RESIDENT" >> + construct(construct( + parenthesized(Parser{}))) || + ("DEVICE_TYPE"_tok || "DTYPE"_tok) >> + construct(construct(parenthesized( + "*" >> construct>>()))) || + ("DEVICE_TYPE"_tok || "DTYPE"_tok) >> + construct(construct( + parenthesized(maybe(nonemptyList(name))))) || + "FINALIZE" >> construct(construct()) || + "FIRSTPRIVATE" >> construct(construct( + parenthesized(Parser{}))) || + "GANG" >> construct(construct( + maybe(parenthesized(Parser{})))) || + "HOST" >> construct(construct( + parenthesized(Parser{}))) || + "IF" >> construct( + construct(parenthesized(scalarLogicalExpr))) || + "IF_PRESENT" >> construct(construct()) || + "INDEPENDENT" >> + construct(construct()) || + "LINK" >> construct(construct( + parenthesized(Parser{}))) || + "NO_CREATE" >> construct(construct( + parenthesized(Parser{}))) || + "NOHOST" >> construct(construct()) || + "NUM_GANGS" >> construct(construct( + parenthesized(scalarIntExpr))) || + "NUM_WORKERS" >> construct(construct( + parenthesized(scalarIntExpr))) || + "PRESENT" >> construct(construct( + parenthesized(Parser{}))) || + "PRIVATE" >> construct(construct( + parenthesized(Parser{}))) || + "READ" >> construct(construct()) || + "REDUCTION" >> construct(construct( + parenthesized(construct( + Parser{} / ":", + Parser{})))) || + "SELF" >> construct(construct( + maybe(parenthesized(scalarLogicalExpr)))) || + "SEQ" >> construct(construct()) || + "TILE" >> construct(construct( + parenthesized(Parser{}))) || + "USE_DEVICE" >> construct(construct( + parenthesized(Parser{}))) || + "VECTOR_LENGTH" >> construct(construct( + parenthesized(scalarIntExpr))) || + "VECTOR" >> + construct(construct(maybe( + parenthesized(("LENGTH:" >> scalarIntExpr || scalarIntExpr))))) || + "WAIT" >> construct(construct( + maybe(Parser{}))) || + "WORKER" >> + construct(construct(maybe( + parenthesized(("NUM:" >> scalarIntExpr || scalarIntExpr))))) || + "WRITE" >> construct(construct())) + +TYPE_PARSER( + construct(designator) || construct("/" >> name / "/")) + +TYPE_PARSER(construct(nonemptyList(Parser{}))) + +TYPE_PARSER(construct( + maybe(Parser{}), Parser{})) + +TYPE_PARSER(construct( + maybe("DEVNUM:" >> scalarIntExpr / ":"), nonemptyList(scalarIntExpr))) + +// 2.9 (1609) size-expr is one of: +// int-expr +TYPE_PARSER(construct(scalarIntExpr) || + construct("*" >> maybe(scalarIntExpr))) +TYPE_PARSER(construct(nonemptyList(Parser{}))) + +// 2.9 (1607) gang-arg is one of: +// [num:]int-expr +// static:size-expr +TYPE_PARSER(construct(maybe(scalarIntExpr), + maybe(","_tok / "STATIC:" >> Parser{})) || + construct(maybe("NUM:" >> scalarIntExpr), + maybe(","_tok / "STATIC:" >> Parser{}))) + +// 2.5.13 Reduction +TYPE_PARSER(construct(Parser{}) || + construct(Parser{})) + +// 2.5.14 Default clause +TYPE_PARSER(construct( + parenthesized(first("NONE" >> pure(AccDefaultClause::Arg::None), + "PRESENT" >> pure(AccDefaultClause::Arg::Present))))) + +// Modifier for copyin, copyout, cache and create +TYPE_PARSER(construct( + first("ZERO:" >> pure(AccDataModifier::Modifier::Zero), + "READONLY:" >> pure(AccDataModifier::Modifier::ReadOnly)))) + +// Combined directives +TYPE_PARSER(sourced(construct( + first("KERNELS LOOP" >> pure(llvm::acc::Directive::ACCD_kernels_loop), + "PARALLEL LOOP" >> pure(llvm::acc::Directive::ACCD_parallel_loop), + "SERIAL LOOP" >> pure(llvm::acc::Directive::ACCD_serial_loop))))) + +// Block directives +TYPE_PARSER(sourced(construct( + first("DATA" >> pure(llvm::acc::Directive::ACCD_data), + "HOST_DATA" >> pure(llvm::acc::Directive::ACCD_host_data), + "KERNELS" >> pure(llvm::acc::Directive::ACCD_kernels), + "PARALLEL" >> pure(llvm::acc::Directive::ACCD_parallel), + "SERIAL" >> pure(llvm::acc::Directive::ACCD_serial))))) + +// Standalone directives +TYPE_PARSER(sourced(construct( + first("ENTER DATA" >> pure(llvm::acc::Directive::ACCD_enter_data), + "EXIT DATA" >> pure(llvm::acc::Directive::ACCD_exit_data), + "INIT" >> pure(llvm::acc::Directive::ACCD_init), + "SHUTDOWN" >> pure(llvm::acc::Directive::ACCD_shutdown), + "SET" >> pure(llvm::acc::Directive::ACCD_set), + "UPDATE" >> pure(llvm::acc::Directive::ACCD_update))))) + +// Loop directives +TYPE_PARSER(sourced(construct( + first("LOOP" >> pure(llvm::acc::Directive::ACCD_loop))))) + +TYPE_PARSER(construct( + sourced(Parser{}), Parser{})) + +TYPE_PARSER( + construct(sourced(Parser{}))) + +// 2.15.1 Routine directive +TYPE_PARSER(sourced(construct(verbatim("ROUTINE"_tok), + maybe(parenthesized(name)), Parser{}))) + +// 2.10 Cache directive +TYPE_PARSER(sourced( + construct(sourced(construct("CACHE"_tok)), + parenthesized(Parser{})))) + +// 2.11 Combined constructs +TYPE_PARSER(startAccLine >> construct(sourced( + "END"_tok >> Parser{}))) + +TYPE_PARSER(construct( + sourced(Parser{}), Parser{})) + +TYPE_PARSER(construct( + Parser{} / endAccLine, block, + maybe(Parser{} / endAccLine))) + +// 2.12 Atomic constructs +TYPE_PARSER(construct(startAccLine >> "END ATOMIC"_tok)) + +TYPE_PARSER("ATOMIC" >> + construct(verbatim("READ"_tok) / endAccLine, + statement(assignmentStmt), maybe(Parser{} / endAccLine))) + +TYPE_PARSER("ATOMIC" >> + construct(verbatim("WRITE"_tok) / endAccLine, + statement(assignmentStmt), maybe(Parser{} / endAccLine))) + +TYPE_PARSER("ATOMIC" >> + construct(maybe(verbatim("UPDATE"_tok)) / endAccLine, + statement(assignmentStmt), maybe(Parser{} / endAccLine))) + +TYPE_PARSER("ATOMIC" >> + construct(verbatim("CAPTURE"_tok) / endAccLine, + statement(assignmentStmt), statement(assignmentStmt), + Parser{} / endAccLine)) + +TYPE_PARSER(construct(Parser{}) || + construct(Parser{}) || + construct(Parser{}) || + construct(Parser{})) + +// 2.13 Declare constructs +TYPE_PARSER(sourced(construct( + first("DECLARE" >> pure(llvm::acc::Directive::ACCD_declare))))) + +// [Clause, [Clause], ...] +TYPE_PARSER(sourced(construct( + many(maybe(","_tok) >> sourced(Parser{}))))) + +// 2.16.3 Wait directive +TYPE_PARSER(sourced(construct( + sourced(construct("WAIT"_tok)), + maybe(parenthesized(Parser{})), Parser{}))) + +// Block Constructs +TYPE_PARSER(sourced(construct( + sourced(Parser{}), Parser{}))) + +TYPE_PARSER(startAccLine >> sourced(construct("END"_tok >> + sourced(Parser{})))) + +TYPE_PARSER(construct( + Parser{} / endAccLine, block, + Parser{} / endAccLine)) + +// Standalone constructs +TYPE_PARSER(construct( + sourced(Parser{}), Parser{})) + +// Standalone declarative constructs +TYPE_PARSER(construct( + sourced(Parser{}), Parser{})) + +TYPE_PARSER( + startAccLine >> sourced(construct( + Parser{}))) + +// OpenACC constructs +TYPE_CONTEXT_PARSER("OpenACC construct"_en_US, + startAccLine >> + first(construct(Parser{}), + construct(Parser{}), + construct(Parser{}), + construct(Parser{}), + construct(Parser{}), + construct(Parser{}), + construct(Parser{}), + construct(Parser{}))) +} // namespace Fortran::parser 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 @@ -23,10 +23,6 @@ constexpr auto startOmpLine = skipStuffBeforeStatement >> "!$OMP "_sptok; constexpr auto endOmpLine = space >> endOfLine; -template constexpr decltype(auto) verbatim(A x) { - return sourced(construct(x)); -} - // OpenMP Clauses // 2.15.3.1 DEFAULT (PRIVATE | FIRSTPRIVATE | SHARED | NONE) TYPE_PARSER(construct( diff --git a/flang/lib/Parser/parsing.cpp b/flang/lib/Parser/parsing.cpp --- a/flang/lib/Parser/parsing.cpp +++ b/flang/lib/Parser/parsing.cpp @@ -67,6 +67,9 @@ prescanner.set_fixedForm(options.isFixedForm) .set_fixedFormColumnLimit(options.fixedFormColumns) .AddCompilerDirectiveSentinel("dir$"); + if (options.features.IsEnabled(LanguageFeature::OpenACC)) { + prescanner.AddCompilerDirectiveSentinel("$acc"); + } if (options.features.IsEnabled(LanguageFeature::OpenMP)) { prescanner.AddCompilerDirectiveSentinel("$omp"); prescanner.AddCompilerDirectiveSentinel("$"); // OMP conditional line diff --git a/flang/lib/Parser/program-parsers.cpp b/flang/lib/Parser/program-parsers.cpp --- a/flang/lib/Parser/program-parsers.cpp +++ b/flang/lib/Parser/program-parsers.cpp @@ -60,7 +60,8 @@ // [use-stmt]... [import-stmt]... [implicit-part] // [declaration-construct]... TYPE_CONTEXT_PARSER("specification part"_en_US, - construct(many(openmpDeclarativeConstruct), + construct(many(openaccDeclarativeConstruct), + many(openmpDeclarativeConstruct), many(statement(indirect(Parser{}))), many(unambiguousStatement(indirect(Parser{}))), implicitPart, many(declarationConstruct))) @@ -75,10 +76,10 @@ // are in contexts that impose constraints on the kinds of statements that // are allowed, and so we have a variant production for declaration-construct // that implements those constraints. -constexpr auto execPartLookAhead{ - first(actionStmt >> ok, ompEndLoopDirective >> ok, openmpConstruct >> ok, - "ASSOCIATE ("_tok, "BLOCK"_tok, "SELECT"_tok, "CHANGE TEAM"_sptok, - "CRITICAL"_tok, "DO"_tok, "IF ("_tok, "WHERE ("_tok, "FORALL ("_tok)}; +constexpr auto execPartLookAhead{first(actionStmt >> ok, + ompEndLoopDirective >> ok, openaccConstruct >> ok, openmpConstruct >> ok, + "ASSOCIATE ("_tok, "BLOCK"_tok, "SELECT"_tok, "CHANGE TEAM"_sptok, + "CRITICAL"_tok, "DO"_tok, "IF ("_tok, "WHERE ("_tok, "FORALL ("_tok)}; constexpr auto declErrorRecovery{ stmtErrorRecoveryStart >> !execPartLookAhead >> skipStmtErrorRecovery}; constexpr auto misplacedSpecificationStmt{Parser{} >> @@ -126,7 +127,8 @@ // specialized error recovery in the event of a spurious executable // statement. constexpr auto limitedSpecificationPart{inContext("specification part"_en_US, - construct(many(openmpDeclarativeConstruct), + construct(many(openaccDeclarativeConstruct), + many(openmpDeclarativeConstruct), many(statement(indirect(Parser{}))), many(unambiguousStatement(indirect(Parser{}))), implicitPart, many(limitedDeclarationConstruct)))}; @@ -151,6 +153,8 @@ construct( statement(indirect(typeDeclarationStmt))), construct(indirect(Parser{})), + construct( + indirect(openaccDeclarativeConstruct)), construct(indirect(openmpDeclarativeConstruct)), construct(indirect(compilerDirective)))) diff --git a/flang/lib/Parser/stmt-parser.h b/flang/lib/Parser/stmt-parser.h --- a/flang/lib/Parser/stmt-parser.h +++ b/flang/lib/Parser/stmt-parser.h @@ -80,6 +80,7 @@ constexpr auto executionPartErrorRecovery{stmtErrorRecoveryStart >> !"END"_tok >> !"CONTAINS"_tok >> !"ELSE"_tok >> !"CASE"_tok >> !"TYPE IS"_tok >> !"CLASS"_tok >> !"RANK"_tok >> + !("!$ACC "_sptok >> "END"_tok) >> !("!$OMP "_sptok >> ("END"_tok || "SECTION"_id)) >> skipBadLine}; // END statement error recovery diff --git a/flang/lib/Parser/token-parsers.h b/flang/lib/Parser/token-parsers.h --- a/flang/lib/Parser/token-parsers.h +++ b/flang/lib/Parser/token-parsers.h @@ -664,5 +664,9 @@ constexpr auto rawHollerithLiteral{ deprecated(HollerithLiteral{})}; +template constexpr decltype(auto) verbatim(A x) { + return sourced(construct(x)); +} + } // namespace Fortran::parser #endif // FORTRAN_PARSER_TOKEN_PARSERS_H_ diff --git a/flang/lib/Parser/type-parsers.h b/flang/lib/Parser/type-parsers.h --- a/flang/lib/Parser/type-parsers.h +++ b/flang/lib/Parser/type-parsers.h @@ -130,6 +130,8 @@ constexpr Parser entryStmt; // R1541 constexpr Parser containsStmt; // R1543 constexpr Parser compilerDirective; +constexpr Parser openaccConstruct; +constexpr Parser openaccDeclarativeConstruct; constexpr Parser openmpConstruct; constexpr Parser openmpDeclarativeConstruct; constexpr Parser ompEndLoopDirective; 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 @@ -1777,6 +1777,375 @@ } Walk(std::get(x.t)); } + + // OpenACC Directives & Clauses + void Unparse(const AccAtomicCapture &x) { + BeginOpenACC(); + Word("!$ACC CAPTURE"); + Put("\n"); + EndOpenACC(); + Walk(std::get(x.t)); + Put("\n"); + Walk(std::get(x.t)); + BeginOpenACC(); + Word("!$ACC END ATOMIC\n"); + EndOpenACC(); + } + void Unparse(const AccAtomicRead &x) { + BeginOpenACC(); + Word("!$ACC ATOMIC READ"); + Put("\n"); + EndOpenACC(); + Walk(std::get>(x.t)); + BeginOpenACC(); + Walk(std::get>(x.t), "!$ACC END ATOMIC\n"); + EndOpenACC(); + } + void Unparse(const AccAtomicWrite &x) { + BeginOpenACC(); + Word("!$ACC ATOMIC WRITE"); + Put("\n"); + EndOpenACC(); + Walk(std::get>(x.t)); + BeginOpenACC(); + Walk(std::get>(x.t), "!$ACC END ATOMIC\n"); + EndOpenACC(); + } + void Unparse(const AccAtomicUpdate &x) { + BeginOpenACC(); + Word("!$ACC ATOMIC UPDATE"); + Put("\n"); + EndOpenACC(); + Walk(std::get>(x.t)); + BeginOpenACC(); + Walk(std::get>(x.t), "!$ACC END ATOMIC\n"); + EndOpenACC(); + } + void Unparse(const llvm::acc::Directive &x) { + Word(llvm::acc::getOpenACCDirectiveName(x).str()); + } + void Before(const AccClause::Auto &) { Word("AUTO"); } + void Before(const AccClause::Capture &) { Word("CAPTURE"); } + void Before(const AccClause::Finalize &) { Word("FINALIZE"); } + void Before(const AccClause::IfPresent &) { Word("IF_PRESENT"); } + void Before(const AccClause::Independent &) { Word("INDEPENDENT"); } + void Before(const AccClause::NoHost &) { Word("NOHOST"); } + void Before(const AccClause::Read &) { Word("READ"); } + void Before(const AccClause::Seq &) { Word("SEQ"); } + void Before(const AccClause::Write &) { Word("WRITE"); } + void Before(const AccClause::Unknown &) { Word("UNKNOWN"); } + void Unparse(const AccClause::Attach &x) { + Word("ATTACH"); + Put("("); + Walk(x.v); + Put(")"); + } + void Unparse(const AccClause::Bind &x) { + Word("BIND"); + Put("("); + Walk(x.v); + Put(")"); + } + void Unparse(const AccClause::Collapse &x) { + Word("COLLAPSE"); + Put("("); + Walk(x.v); + Put(")"); + } + void Unparse(const AccClause::Copy &x) { + Word("COPY"); + Put("("); + Walk(x.v); + Put(")"); + } + void Unparse(const AccClause::Copyin &x) { + Word("COPYIN"); + Put("("); + Walk(x.v); + Put(")"); + } + void Unparse(const AccClause::Copyout &x) { + Word("COPYOUT"); + Put("("); + Walk(x.v); + Put(")"); + } + void Unparse(const AccClause::Create &x) { + Word("CREATE"); + Put("("); + Walk(x.v); + Put(")"); + } + void Unparse(const AccClause::Default &x) { + Word("DEFAULT"); + Put("("); + Walk(x.v); + Put(")"); + } + void Unparse(const AccClause::Delete &x) { + Word("DELETE"); + Put("("); + Walk(x.v); + Put(")"); + } + void Unparse(const AccClause::Detach &x) { + Word("DETACH"); + Put("("); + Walk(x.v); + Put(")"); + } + void Unparse(const AccClause::Device &x) { + Word("DEVICE"); + Put("("); + Walk(x.v); + Put(")"); + } + void Unparse(const AccClause::DevicePtr &x) { + Word("DEVICEPTR"); + Put("("); + Walk(x.v); + Put(")"); + } + void Unparse(const AccClause::DeviceResident &x) { + Word("DEVICE_RESIDENT"); + Put("("); + Walk(x.v); + Put(")"); + } + void Unparse(const AccClause::FirstPrivate &x) { + Word("FIRSTPRIVATE"); + Put("("); + Walk(x.v); + Put(")"); + } + void Unparse(const AccClause::Host &x) { + Word("HOST"); + Put("("); + Walk(x.v); + Put(")"); + } + void Unparse(const AccClause::If &x) { + Word("IF"); + Put("("); + Walk(x.v); + Put(")"); + } + void Unparse(const AccClause::Link &x) { + Word("LINK"); + Put("("); + Walk(x.v); + Put(")"); + } + void Unparse(const AccClause::NumGangs &x) { + Word("NUM_GANGS"); + Put("("); + Walk(x.v); + Put(")"); + } + void Unparse(const AccClause::NumWorkers &x) { + Word("NUM_WORKERS"); + Put("("); + Walk(x.v); + Put(")"); + } + void Unparse(const AccClause::Present &x) { + Word("PRESENT"); + Put("("); + Walk(x.v); + Put(")"); + } + void Unparse(const AccClause::Private &x) { + Word("PRIVATE"); + Put("("); + Walk(x.v); + Put(")"); + } + void Unparse(const AccClause::Reduction &x) { + Word("REDUCTION"); + Put("("); + Walk(x.v); + Put(")"); + } + void Unparse(const AccClause::VectorLength &x) { + Word("VECTOR_LENGTH"); + Put("("); + Walk(x.v); + Put(")"); + } + void Unparse(const AccClause::Async &x) { + Word("ASYNC"); + Walk("(", x.v, ")"); + } + void Unparse(const AccClause::DefaultAsync &x) { + Word("DEFAULT_ASYNC"); + Put("("); + Walk(x.v); + Put(")"); + } + void Unparse(const AccClause::DeviceNum &x) { + Word("DEVICE_NUM"); + Put("("); + Walk(x.v); + Put(")"); + } + void Unparse(const AccClause::Gang &x) { + Word("GANG"); + Walk("(", x.v, ")"); + } + void Unparse(const AccClause::NoCreate &x) { + Word("NO_CREATE"); + Put("("); + Walk(x.v); + Put(")"); + } + void Unparse(const AccClause::UseDevice &x) { + Word("USE_DEVICE"); + Put("("); + Walk(x.v); + Put(")"); + } + void Unparse(const AccClause::Self &x) { + Word("SELF"); + Walk("(", x.v, ")"); + } + void Unparse(const AccClause::Vector &x) { + Word("VECTOR"); + Walk("(", x.v, ")"); + } + void Unparse(const AccClause::Wait &x) { + Word("WAIT"); + Walk("(", x.v, ")"); + } + void Unparse(const AccClause::Worker &x) { + Word("WORKER"); + Walk("(", x.v, ")"); + } + void Unparse(const AccClause::DeviceType &x) { + Word("DEVICE_TYPE"); + Put("("); + if (x.v.has_value()) + Walk(x.v); + else + Put("*"); + Put(")"); + } + void Unparse(const AccObjectListWithModifier &x) { + Walk(std::get>(x.t), ":"); + Walk(std::get(x.t)); + } + void Unparse(const AccDataModifier::Modifier &x) { + Word(AccDataModifier::EnumToString(x)); + } + void Unparse(const AccDefaultClause &x) { + switch (x.v) { + case AccDefaultClause::Arg::None: + Put("NONE"); + break; + case AccDefaultClause::Arg::Present: + Put("PRESENT"); + break; + } + } + void Unparse(const AccClauseList &x) { Walk(" ", x.v, " "); } + void Unparse(const AccGangArgument &x) { + Walk("NUM:", std::get>(x.t)); + Walk(", STATIC:", std::get>(x.t)); + } + void Unparse(const OpenACCBlockConstruct &x) { + BeginOpenACC(); + Word("!$ACC "); + Walk(std::get(x.t)); + Put("\n"); + EndOpenACC(); + Walk(std::get(x.t), ""); + BeginOpenACC(); + Word("!$ACC END "); + Walk(std::get(x.t)); + Put("\n"); + EndOpenACC(); + } + void Unparse(const OpenACCLoopConstruct &x) { + BeginOpenACC(); + Word("!$ACC "); + Walk(std::get(x.t)); + Put("\n"); + EndOpenACC(); + Walk(std::get>(x.t)); + } + void Unparse(const AccBeginLoopDirective &x) { + Walk(std::get(x.t)); + Walk(std::get(x.t)); + } + void Unparse(const OpenACCStandaloneConstruct &x) { + BeginOpenACC(); + Word("!$ACC "); + Walk(std::get(x.t)); + Walk(std::get(x.t)); + Put("\n"); + EndOpenACC(); + } + void Unparse(const OpenACCStandaloneDeclarativeConstruct &x) { + BeginOpenACC(); + Word("!$ACC "); + Walk(std::get(x.t)); + Walk(std::get(x.t)); + Put("\n"); + EndOpenACC(); + } + void Unparse(const OpenACCCombinedConstruct &x) { + BeginOpenACC(); + Word("!$ACC "); + Walk(std::get(x.t)); + Put("\n"); + EndOpenACC(); + Walk(std::get(x.t), ""); + BeginOpenACC(); + Word("!$ACC END "); + Walk(std::get>(x.t)); + Put("\n"); + EndOpenACC(); + } + void Unparse(const OpenACCRoutineConstruct &x) { + BeginOpenACC(); + Word("!$ACC ROUTINE"); + Walk("(", std::get>(x.t), ")"); + Walk(std::get(x.t)); + Put("\n"); + EndOpenACC(); + } + void Unparse(const AccObject &x) { + std::visit(common::visitors{ + [&](const Designator &y) { Walk(y); }, + [&](const Name &y) { Put("/"), Walk(y), Put("/"); }, + }, + x.u); + } + void Unparse(const AccObjectList &x) { Walk(x.v, ","); } + void Unparse(const AccObjectListWithReduction &x) { + Walk(std::get(x.t)); + Put(":"); + Walk(std::get(x.t)); + } + void Unparse(const OpenACCCacheConstruct &x) { + BeginOpenACC(); + Word("!$ACC "); + Word("CACHE("); + Walk(std::get(x.t)); + Put(")"); + Put("\n"); + EndOpenACC(); + } + void Unparse(const OpenACCWaitConstruct &x) { + BeginOpenACC(); + Word("!$ACC "); + Word("WAIT("); + Walk(std::get>(x.t)); + Walk(std::get(x.t)); + Put(")"); + Put("\n"); + EndOpenACC(); + } + // OpenMP Clauses & Directives void Unparse(const OmpObject &x) { std::visit(common::visitors{ @@ -2522,6 +2891,8 @@ } void BeginOpenMP() { openmpDirective_ = true; } void EndOpenMP() { openmpDirective_ = false; } + void BeginOpenACC() { openaccDirective_ = true; } + void EndOpenACC() { openaccDirective_ = false; } // Call back to the traversal framework. template void Walk(const T &x) { @@ -2591,6 +2962,7 @@ std::set structureComponents_; Encoding encoding_{Encoding::UTF_8}; bool capitalizeKeywords_{true}; + bool openaccDirective_{false}; bool openmpDirective_{false}; bool backslashEscapes_{false}; preStatementType *preStatement_{nullptr}; @@ -2599,7 +2971,7 @@ void UnparseVisitor::Put(char ch) { int sav = indent_; - if (openmpDirective_) { + if (openmpDirective_ || openaccDirective_) { indent_ = 0; } if (column_ <= 1) { @@ -2620,13 +2992,16 @@ if (openmpDirective_) { out_ << "!$OMP&"; column_ = 8; + } else if (openaccDirective_) { + out_ << "!$ACC&"; + column_ = 8; } else { out_ << '&'; column_ = indent_ + 3; } } out_ << ch; - if (openmpDirective_) { + if (openmpDirective_ || openaccDirective_) { indent_ = sav; } } 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 @@ -6010,7 +6010,8 @@ Walk(std::get<1>(x.t)); Walk(std::get<2>(x.t)); Walk(std::get<3>(x.t)); - const std::list &decls{std::get<4>(x.t)}; + Walk(std::get<4>(x.t)); + const std::list &decls{std::get<5>(x.t)}; for (const auto &decl : decls) { if (const auto *spec{ std::get_if(&decl.u)}) { diff --git a/flang/test/Semantics/acc-validity.f90 b/flang/test/Semantics/acc-validity.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/acc-validity.f90 @@ -0,0 +1,169 @@ +! RUN: %S/test_errors.sh %s %t %f18 -fopenacc + +! Check OpenACC clause validity for the following construct and directive: +! 2.6.5 Data +! 2.5.1 Parallel +! 2.5.2 Kernels +! 2.5.3 Serial +! 2.15.1 Routine +! 2.11 Parallel Loop +! 2.11 Kernels Loop +! 2.11 Serial Loop + +program openacc_clause_validity + + implicit none + + integer :: i, j + integer :: N = 256 + + !$acc declare + real(8) :: a(256) + + !$acc enter data + + !$acc enter data copyin(zero: i) + + !$acc enter data create(readonly: i) + + !$acc data copyout(readonly: i) + !$acc end data + + !$acc enter data copyin(i) copyout(i) + + !$acc data copy(i) if(.true.) if(.true.) + !$acc end data + + !$acc exit data + + !$acc host_data + !$acc end host_data + + !$acc set + + !$acc data + !$acc end data + + !$acc data copyin(i) + !$acc end data + + !$acc data copyin(i) + + !$acc end parallel + + !$acc update device(i) device_type(*) async + + + !$acc update device(i) device_type(*) if(.TRUE.) + + !$acc parallel + + !$acc loop seq independent + do i = 1, N + a(i) = 3.14 + end do + !$acc end parallel + + !$acc parallel device_type(*) num_gangs(2) + !$acc loop + do i = 1, N + a(i) = 3.14 + end do + !$acc end parallel + + !$acc parallel + + !$acc loop collapse(-1) + do i = 1, N + do j = 1, N + a(i) = 3.14 + j + end do + end do + !$acc end parallel + + !$acc parallel + + !$acc loop device_type(*) private(i) + do i = 1, N + a(i) = 3.14 + end do + !$acc end parallel + + !$acc parallel + + !$acc loop gang seq + do i = 1, N + a(i) = 3.14 + end do + !$acc end parallel + + + !$acc parallel device_type(*) if(.TRUE.) + !$acc loop + do i = 1, N + a(i) = 3.14 + end do + !$acc end parallel + + + !$acc parallel loop device_type(*) if(.TRUE.) + do i = 1, N + a(i) = 3.14 + end do + !$acc end parallel loop + + !$acc kernels device_type(*) async + do i = 1, N + a(i) = 3.14 + end do + !$acc end kernels + + + !$acc kernels device_type(*) if(.TRUE.) + do i = 1, N + a(i) = 3.14 + end do + !$acc end kernels + + + !$acc kernels loop device_type(*) if(.TRUE.) + do i = 1, N + a(i) = 3.14 + end do + !$acc end kernels loop + + !$acc serial device_type(*) async + do i = 1, N + a(i) = 3.14 + end do + !$acc end serial + + + !$acc serial device_type(*) if(.TRUE.) + do i = 1, N + a(i) = 3.14 + end do + !$acc end serial + + + !$acc serial loop device_type(*) if(.TRUE.) + do i = 1, N + a(i) = 3.14 + end do + !$acc end serial loop + + contains + + subroutine sub1(a) + real :: a(:) + + !$acc routine + end subroutine sub1 + + subroutine sub2(a) + real :: a(:) + + !$acc routine seq device_type(*) nohost + end subroutine sub2 + +end program openacc_clause_validity \ No newline at end of file diff --git a/flang/tools/f18-parse-demo/CMakeLists.txt b/flang/tools/f18-parse-demo/CMakeLists.txt --- a/flang/tools/f18-parse-demo/CMakeLists.txt +++ b/flang/tools/f18-parse-demo/CMakeLists.txt @@ -1,4 +1,5 @@ set(LLVM_LINK_COMPONENTS + FrontendOpenACC FrontendOpenMP ) diff --git a/flang/tools/f18/CMakeLists.txt b/flang/tools/f18/CMakeLists.txt --- a/flang/tools/f18/CMakeLists.txt +++ b/flang/tools/f18/CMakeLists.txt @@ -1,4 +1,5 @@ set(LLVM_LINK_COMPONENTS + FrontendOpenACC FrontendOpenMP Support ) @@ -59,7 +60,7 @@ set(FLANG_INTRINSIC_MODULES_DIR ${FLANG_BINARY_DIR}/include/flang) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/flang.sh.in ${CMAKE_BINARY_DIR}/tools/flang/bin/flang @ONLY) -file(COPY ${CMAKE_BINARY_DIR}/tools/flang/bin/flang DESTINATION ${CMAKE_BINARY_DIR}/bin FILE_PERMISSIONS OWNER_EXECUTE OWNER_READ OWNER_WRITE) +file(COPY ${CMAKE_BINARY_DIR}/tools/flang/bin/flang DESTINATION ${CMAKE_BINARY_DIR}/bin FILE_PERMISSIONS OWNER_EXECUTE OWNER_READ OWNER_WRITE) # The flang script to be installed needs a different path to the headers. set(FLANG_INTRINSIC_MODULES_DIR ${CMAKE_INSTALL_PREFIX}/include/flang) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/flang.sh.in ${FLANG_BINARY_DIR}/bin/flang-install.sh @ONLY) diff --git a/flang/tools/f18/f18.cpp b/flang/tools/f18/f18.cpp --- a/flang/tools/f18/f18.cpp +++ b/flang/tools/f18/f18.cpp @@ -468,6 +468,9 @@ } else if (arg == "-Mstandard" || arg == "-std=f95" || arg == "-std=f2003" || arg == "-std=f2008" || arg == "-std=legacy") { driver.warnOnNonstandardUsage = true; + } else if (arg == "-fopenacc") { + options.features.Enable(Fortran::common::LanguageFeature::OpenACC); + options.predefinitions.emplace_back("_OPENACC", "201911"); } else if (arg == "-fopenmp") { options.features.Enable(Fortran::common::LanguageFeature::OpenMP); options.predefinitions.emplace_back("_OPENMP", "201511"); diff --git a/llvm/include/llvm/CMakeLists.txt b/llvm/include/llvm/CMakeLists.txt --- a/llvm/include/llvm/CMakeLists.txt +++ b/llvm/include/llvm/CMakeLists.txt @@ -1,6 +1,6 @@ add_subdirectory(IR) add_subdirectory(Support) -add_subdirectory(Frontend/OpenMP) +add_subdirectory(Frontend) # If we're doing an out-of-tree build, copy a module map for generated # header files into the build area. diff --git a/llvm/include/llvm/Frontend/CMakeLists.txt b/llvm/include/llvm/Frontend/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/Frontend/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(OpenACC) +add_subdirectory(OpenMP) diff --git a/llvm/include/llvm/Frontend/Directive/DirectiveBase.td b/llvm/include/llvm/Frontend/Directive/DirectiveBase.td --- a/llvm/include/llvm/Frontend/Directive/DirectiveBase.td +++ b/llvm/include/llvm/Frontend/Directive/DirectiveBase.td @@ -59,6 +59,9 @@ // Optional class holding value of the clause in clang AST. string clangClass = ?; + // Optional class holding value of the clause in flang AST. + string flangClass = ?; + // Is clause implicit? If clause is set as implicit, the default kind will // be return in getClauseKind instead of their own kind. bit isImplicit = 0; diff --git a/llvm/include/llvm/Frontend/OpenACC/ACC.td b/llvm/include/llvm/Frontend/OpenACC/ACC.td new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/Frontend/OpenACC/ACC.td @@ -0,0 +1,604 @@ +//===-- ACC.td - OpenACC directive definition file ---------*- tablegen -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This is the definition file for OpenACC directives and clauses. +// +//===----------------------------------------------------------------------===// + +include "llvm/Frontend/Directive/DirectiveBase.td" + +//===----------------------------------------------------------------------===// +// Definition of general OpenACC information +//===----------------------------------------------------------------------===// + +def OpenACC : DirectiveLanguage { + let name = "OpenACC"; + let cppNamespace = "acc"; // final namespace will be llvm::acc + let directivePrefix = "ACCD_"; + let clausePrefix = "ACCC_"; + let makeEnumAvailableInNamespace = 1; + let enableBitmaskEnumInNamespace = 1; + let includeHeader = "llvm/Frontend/OpenACC/ACC.h.inc"; + let clauseEnumSetClass = "AccClauseSet"; +} + +//===----------------------------------------------------------------------===// +// Definition of OpenACC clauses +//===----------------------------------------------------------------------===// + +// 2.9.6 +def ACCC_Auto : Clause<"auto"> {} + +// 2.16.1 +def ACCC_Async : Clause<"async"> { + let flangClass = "std::optional"; +} + +// 2.7.11 +def ACCC_Attach : Clause<"attach"> { + let flangClass = "AccObjectList"; +} + +// 2.15.1 +def ACCC_Bind : Clause<"bind"> { + let flangClass = "Name"; +} + +// 2.12 +def ACCC_Capture : Clause<"capture"> { +} + +// 2.9.1 +def ACCC_Collapse : Clause<"collapse"> { + let flangClass = "ScalarIntConstantExpr"; +} + +// 2.7.5 +def ACCC_Copy : Clause<"copy"> { + let flangClass = "AccObjectList"; +} +// 2.7.6 +def ACCC_Copyin : Clause<"copyin"> { + let flangClass = "AccObjectListWithModifier"; +} + +// 2.7.7 +def ACCC_Copyout : Clause<"copyout"> { + let flangClass = "AccObjectListWithModifier"; +} + +// 2.7.8 +def ACCC_Create : Clause<"create"> { + let flangClass = "AccObjectListWithModifier"; +} + +// 2.5.14 +def ACCC_Default : Clause<"default"> { + let flangClass = "AccDefaultClause"; +} + +// 2.4.12 +def ACCC_DefaultAsync : Clause<"default_async"> { + let flangClass = "ScalarIntExpr"; +} + +// 2.7.10 +def ACCC_Delete : Clause<"delete"> { + let flangClass = "AccObjectList"; +} + +// 2.7.12 +def ACCC_Detach : Clause<"detach"> { + let flangClass = "AccObjectList"; +} + +// 2.14.4 +def ACCC_Device : Clause<"device"> { + let flangClass = "AccObjectList"; +} + +// 2.14.1 +def ACCC_DeviceNum : Clause<"devicenum"> { + let flangClass = "ScalarIntConstantExpr"; +} + +// 2.7.3 +def ACCC_DevicePtr : Clause<"deviceptr"> { + let flangClass = "AccObjectList"; +} + +// 2.13 +def ACCC_DeviceResident : Clause<"device_resident"> { + let flangClass = "AccObjectList"; +} + +// 2.4 +def ACCC_DeviceType : Clause<"device_type"> { + // (DeviceType, "*" + let flangClass = "std::optional>"; +} + +// 2.6.6 +def ACCC_Finalize : Clause<"finalize"> {} + +// 2.5.12 +def ACCC_FirstPrivate : Clause<"firstprivate"> { + let flangClass = "AccObjectList"; +} + +// 2.9.2 +def ACCC_Gang : Clause<"gang"> { + let flangClass = "std::optional"; +} + +// 2.14.4 +def ACCC_Host : Clause<"host"> { + let flangClass = "AccObjectList"; +} + +// 2.5.4 +def ACCC_If : Clause <"if"> { + let flangClass = "ScalarLogicalExpr"; +} + +// 2.14.4 +def ACCC_IfPresent : Clause<"if_present"> {} + +// 2.9.9 +def ACCC_Independent : Clause<"independent"> {} + +// 2.13 +def ACCC_Link : Clause<"link"> { + let flangClass = "AccObjectList"; +} + +// 2.7.9 +def ACCC_NoCreate : Clause<"no_create"> { + let flangClass = "AccObjectList"; +} + +// 2.15.1 +def ACCC_NoHost : Clause<"nohost"> {} + +// 2.5.8 +def ACCC_NumGangs : Clause<"num_gangs"> { + let flangClass = "ScalarIntExpr"; +} + +// 2.5.9 +def ACCC_NumWorkers : Clause<"num_workers"> { + let flangClass = "ScalarIntExpr"; +} + +// 2.7.4 +def ACCC_Present : Clause<"present"> { + let flangClass = "AccObjectList"; +} + +// 2.5.11 +def ACCC_Private : Clause<"private"> { + let flangClass = "AccObjectList"; +} + +// 2.9.7 +def ACCC_Tile : Clause <"tile"> { + let flangClass = "AccSizeExprList"; +} + +// 2.8.1 +def ACCC_UseDevice : Clause <"use_device"> { + let flangClass = "AccObjectList"; +} + +// 2.12 +def ACCC_Read : Clause<"read"> {} + +// 2.5.13 +def ACCC_Reduction : Clause<"reduction"> { + let flangClass = "AccObjectListWithReduction"; +} + +// 2.5.5 +def ACCC_Self : Clause<"self"> { + let flangClass = "std::optional"; +} + +// 2.9.5 +def ACCC_Seq : Clause<"seq"> {} + +// 2.9.4 +def ACCC_Vector : Clause<"vector"> { + let flangClass = "std::optional"; +} + +// 2.5.10 +def ACCC_VectorLength : Clause<"vector_length"> { + let flangClass = "ScalarIntExpr"; +} + +// 2.16.2 +def ACCC_Wait : Clause<"wait"> { + let flangClass = "std::optional"; +} + +// 2.9.3 +def ACCC_Worker: Clause<"worker"> { + let flangClass = "std::optional"; +} + +// 2.12 +def ACCC_Write : Clause<"write"> {} + +def ACCC_Unknown : Clause<"unknown"> { + let isDefault = 1; +} + +//===----------------------------------------------------------------------===// +// Definition of OpenACC directives +//===----------------------------------------------------------------------===// + +// 2.12 +def ACC_Atomic : Directive<"atomic"> {} + +// 2.6.5 +def ACC_Data : Directive<"data"> { + let allowedOnceClauses = [ + VersionedClause + ]; + let requiredClauses = [ + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause + ]; +} + +// 2.13 +def ACC_Declare : Directive<"declare"> { + let allowedClauses = [ + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause + ]; +} + +// 2.5.2 +def ACC_Kernels : Directive<"kernels"> { + let allowedClauses = [ + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause + ]; + let allowedOnceClauses = [ + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause + ]; +} + +// 2.5.1 +def ACC_Parallel : Directive<"parallel"> { + let allowedClauses = [ + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause + ]; + let allowedOnceClauses = [ + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause + ]; +} + +// 2.5.3 +def ACC_Serial : Directive<"serial"> { + let allowedClauses = [ + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause + ]; + let allowedOnceClauses = [ + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause + ]; +} + +// 2.9 +def ACC_Loop : Directive<"loop"> { + let allowedClauses = [ + VersionedClause, + VersionedClause + ]; + let allowedOnceClauses = [ + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause + ]; + let allowedExclusiveClauses = [ + VersionedClause, + VersionedClause, + VersionedClause + ]; +} + +// 2.10 +def ACC_Cache : Directive<"cache"> {} + +// 2.14.1 +def ACC_Init : Directive<"init"> { + let allowedOnceClauses = [ + VersionedClause, + VersionedClause, + VersionedClause + ]; +} + +// 2.15.1 +def ACC_Routine : Directive<"routine"> { + let allowedOnceClauses = [ + VersionedClause, + VersionedClause, + VersionedClause + ]; + let requiredClauses = [ + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause + ]; +} + +// 2.14.3 +def ACC_Set : Directive<"set"> { + let allowedOnceClauses = [ + VersionedClause + ]; + let requiredClauses = [ + VersionedClause, + VersionedClause, + VersionedClause + ]; +} + +// 2.14.2 +def ACC_Shutdown : Directive<"shutdown"> { + let allowedOnceClauses = [ + VersionedClause, + VersionedClause, + VersionedClause + ]; +} + +// 2.14.4 +def ACC_Update : Directive<"update"> { + let allowedClauses = [ + VersionedClause, + VersionedClause + ]; + let allowedOnceClauses = [ + VersionedClause, + VersionedClause, + VersionedClause + ]; + let requiredClauses = [ + VersionedClause, + VersionedClause, + VersionedClause + ]; +} + +// 2.16.3 +def ACC_Wait : Directive<"wait"> { + let allowedOnceClauses = [ + VersionedClause, + VersionedClause + ]; +} + +// 2.14.6 +def ACC_EnterData : Directive<"enter data"> { + let allowedOnceClauses = [ + VersionedClause, + VersionedClause, + VersionedClause + ]; + let requiredClauses = [ + VersionedClause, + VersionedClause, + VersionedClause + ]; +} + +// 2.14.7 +def ACC_ExitData : Directive<"exit data"> { + let allowedClauses = [ + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause + ]; + let requiredClauses = [ + VersionedClause, + VersionedClause, + VersionedClause + ]; +} +def ACC_HostData : Directive<"host_data"> { + let allowedClauses = [ + VersionedClause, + VersionedClause + ]; + let requiredClauses = [ + VersionedClause + ]; +} + +// 2.11 +def ACC_KernelsLoop : Directive<"kernels loop"> { + let allowedClauses = [ + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause + ]; + let allowedOnceClauses = [ + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause + ]; + let allowedExclusiveClauses = [ + VersionedClause, + VersionedClause, + VersionedClause + ]; +} + +// 2.11 +def ACC_ParallelLoop : Directive<"parallel loop"> { + let allowedClauses = [ + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause + ]; + let allowedOnceClauses = [ + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause + ]; + let allowedExclusiveClauses = [ + VersionedClause, + VersionedClause, + VersionedClause + ]; +} + +// 2.11 +def ACC_SerialLoop : Directive<"serial loop"> { + let allowedClauses = [ + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause + ]; + let allowedOnceClauses = [ + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause, + VersionedClause + ]; + let allowedExclusiveClauses = [ + VersionedClause, + VersionedClause, + VersionedClause + ]; +} + +def ACC_Unknown : Directive<"unknown"> { + let isDefault = 1; +} \ No newline at end of file diff --git a/llvm/include/llvm/Frontend/OpenACC/CMakeLists.txt b/llvm/include/llvm/Frontend/OpenACC/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/Frontend/OpenACC/CMakeLists.txt @@ -0,0 +1,4 @@ +set(LLVM_TARGET_DEFINITIONS ACC.td) +tablegen(LLVM ACC.h.inc --gen-directive-decl) +tablegen(LLVM ACC.cpp.inc --gen-directive-impl) +add_public_tablegen_target(acc_gen) diff --git a/llvm/lib/Frontend/CMakeLists.txt b/llvm/lib/Frontend/CMakeLists.txt --- a/llvm/lib/Frontend/CMakeLists.txt +++ b/llvm/lib/Frontend/CMakeLists.txt @@ -1 +1,2 @@ +add_subdirectory(OpenACC) add_subdirectory(OpenMP) diff --git a/llvm/lib/Frontend/OpenACC/CMakeLists.txt b/llvm/lib/Frontend/OpenACC/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/llvm/lib/Frontend/OpenACC/CMakeLists.txt @@ -0,0 +1,18 @@ +set(LLVM_TARGET_DEFINITIONS ${LLVM_MAIN_INCLUDE_DIR}/llvm/Frontend/OpenACC/ACC.td) +tablegen(LLVM ACC.cpp --gen-directive-impl) +add_public_tablegen_target(acc_cpp) + +add_llvm_component_library(LLVMFrontendOpenACC + ACC.cpp # Generated by tablegen above + + ADDITIONAL_HEADER_DIRS + ${LLVM_MAIN_INCLUDE_DIR}/llvm/Frontend + ${LLVM_MAIN_INCLUDE_DIR}/llvm/Frontend/OpenACC + + DEPENDS + acc_gen + acc_cpp +) + +target_link_libraries(LLVMFrontendOpenACC LLVMSupport) + diff --git a/llvm/test/TableGen/directive1.td b/llvm/test/TableGen/directive1.td --- a/llvm/test/TableGen/directive1.td +++ b/llvm/test/TableGen/directive1.td @@ -75,6 +75,7 @@ // IMPL: #include "llvm/ADT/StringRef.h" // IMPL-NEXT: #include "llvm/ADT/StringSwitch.h" +// IMPL-NEXT: #include "llvm/Support/ErrorHandling.h" // IMPL-EMPTY: // IMPL-NEXT: using namespace llvm; // IMPL-NEXT: using namespace tdl; diff --git a/llvm/test/TableGen/directive2.td b/llvm/test/TableGen/directive2.td --- a/llvm/test/TableGen/directive2.td +++ b/llvm/test/TableGen/directive2.td @@ -68,6 +68,7 @@ // IMPL-EMPTY: // IMPL-NEXT: #include "llvm/ADT/StringRef.h" // IMPL-NEXT: #include "llvm/ADT/StringSwitch.h" +// IMPL-NEXT: #include "llvm/Support/ErrorHandling.h" // IMPL-EMPTY: // IMPL-NEXT: using namespace llvm; // IMPL-NEXT: using namespace tdl; diff --git a/llvm/utils/TableGen/DirectiveEmitter.cpp b/llvm/utils/TableGen/DirectiveEmitter.cpp --- a/llvm/utils/TableGen/DirectiveEmitter.cpp +++ b/llvm/utils/TableGen/DirectiveEmitter.cpp @@ -492,6 +492,7 @@ OS << "#include \"llvm/ADT/StringRef.h\"\n"; OS << "#include \"llvm/ADT/StringSwitch.h\"\n"; + OS << "#include \"llvm/Support/ErrorHandling.h\"\n"; OS << "\n"; OS << "using namespace llvm;\n"; llvm::SmallVector Namespaces;