diff --git a/flang/lib/Parser/openacc-parsers.cpp b/flang/lib/Parser/openacc-parsers.cpp --- a/flang/lib/Parser/openacc-parsers.cpp +++ b/flang/lib/Parser/openacc-parsers.cpp @@ -22,97 +22,12 @@ 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(Parser{})) || - "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{}))) || - "DEVICE_NUM" >> construct(construct( - parenthesized(scalarIntExpr))) || - "DEVICE_RESIDENT" >> - construct(construct( - parenthesized(Parser{}))) || - ("DEVICE_TYPE"_tok || "DTYPE"_tok) >> - construct(construct( - parenthesized(Parser{}))) || - "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(Parser{})))) || - "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(parenthesized(Parser{})))) || - "WORKER" >> - construct(construct(maybe( - parenthesized(("NUM:" >> scalarIntExpr || scalarIntExpr))))) || - "WRITE" >> construct(construct())) +// Autogenerated clauses parser. Information is taken from ACC.td and the +// parser is generated by tablegen. +// Scalar value parsers are provided by Flang directly. Specific value parsers +// are provided below. +#define GEN_FLANG_CLAUSES_PARSER +#include "llvm/Frontend/OpenACC/ACC.inc" TYPE_PARSER( construct(designator) || construct("/" >> name / "/")) @@ -122,6 +37,9 @@ TYPE_PARSER(construct( maybe(Parser{}), Parser{})) +TYPE_PARSER(construct( + Parser{} / ":", Parser{})) + // 2.16.3 (2485) wait-argument is: // [devnum : int-expr :] [queues :] int-expr-list TYPE_PARSER(construct(maybe("DEVNUM:" >> scalarIntExpr / ":"), @@ -170,13 +88,13 @@ ".NEQV." >> pure(AccReductionOperator::Operator::Neqv))))) // 2.15.1 Bind clause -TYPE_PARSER(sourced(construct(parenthesized(name))) || - sourced(construct(parenthesized(scalarDefaultCharExpr)))) +TYPE_PARSER(sourced(construct(name)) || + sourced(construct(scalarDefaultCharExpr))) // 2.5.14 Default clause -TYPE_PARSER(construct(parenthesized( +TYPE_PARSER(construct( first("NONE" >> pure(llvm::acc::DefaultValue::ACC_Default_none), - "PRESENT" >> pure(llvm::acc::DefaultValue::ACC_Default_present))))) + "PRESENT" >> pure(llvm::acc::DefaultValue::ACC_Default_present)))) // SELF clause is either a simple optional condition for compute construct // or a synonym of the HOST clause for the update directive 2.14.4 holding 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 @@ -74,6 +74,9 @@ // Define an alternative name return in getClauseName function. string alternativeName = ""; + // Define aliases used in the parser. + list aliases = []; + // Optional class holding value of the clause in clang AST. string clangClass = ""; @@ -88,6 +91,7 @@ // List of allowed clause values list allowedClauseValues = []; + // If set to true, value class is part of a list. Single class by default. bit isValueList = false; @@ -101,6 +105,14 @@ // Set clause used by default when unknown. Function returning the kind // of enumeration will use this clause as the default. bit isDefault = false; + + // Prefix before the actual value. Used in the parser generation. + // `clause(prefix: value)` + string prefix = ""; + + // Set the prefix as optional. + // `clause([prefix]: value)` + bit isPrefixOptional = true; } // Hold information about clause validity by version. diff --git a/llvm/include/llvm/Frontend/OpenACC/ACC.td b/llvm/include/llvm/Frontend/OpenACC/ACC.td --- a/llvm/include/llvm/Frontend/OpenACC/ACC.td +++ b/llvm/include/llvm/Frontend/OpenACC/ACC.td @@ -62,20 +62,24 @@ // 2.7.6 def ACCC_Copy : Clause<"copy"> { let flangClass = "AccObjectList"; + let aliases = ["present_or_copy", "pcopy"]; } // 2.7.7 def ACCC_Copyin : Clause<"copyin"> { let flangClass = "AccObjectListWithModifier"; + let aliases = ["present_or_copyin", "pcopyin"]; } // 2.7.8 def ACCC_Copyout : Clause<"copyout"> { let flangClass = "AccObjectListWithModifier"; + let aliases = ["present_or_copyout", "pcopyout"]; } // 2.7.9 def ACCC_Create : Clause<"create"> { let flangClass = "AccObjectListWithModifier"; + let aliases = ["present_or_create", "pcreate"]; } // 2.5.15 @@ -130,6 +134,7 @@ def ACCC_DeviceType : Clause<"device_type"> { let flangClass = "AccDeviceTypeExprList"; let defaultValue = "*"; + let aliases = ["dtype"]; } // 2.6.6 @@ -226,6 +231,7 @@ def ACCC_Vector : Clause<"vector"> { let flangClass = "ScalarIntExpr"; let isValueOptional = true; + let prefix = "length"; } // 2.5.11 @@ -243,6 +249,7 @@ def ACCC_Worker: Clause<"worker"> { let flangClass = "ScalarIntExpr"; let isValueOptional = true; + let prefix = "num"; } // 2.12 diff --git a/llvm/include/llvm/TableGen/DirectiveEmitter.h b/llvm/include/llvm/TableGen/DirectiveEmitter.h --- a/llvm/include/llvm/TableGen/DirectiveEmitter.h +++ b/llvm/include/llvm/TableGen/DirectiveEmitter.h @@ -174,6 +174,16 @@ } bool isImplicit() const { return Def->getValueAsBit("isImplicit"); } + + std::vector getAliases() const { + return Def->getValueAsListOfStrings("aliases"); + } + + StringRef getPrefix() const { return Def->getValueAsString("prefix"); } + + bool isPrefixOptional() const { + return Def->getValueAsBit("isPrefixOptional"); + } }; // Wrapper class that contains VersionedClause's information defined in 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 @@ -196,6 +196,16 @@ // IMPL-EMPTY: // IMPL-NEXT: #endif // GEN_FLANG_CLAUSE_PARSER_KIND_MAP // IMPL-EMPTY: +// IMPL-NEXT: #ifdef GEN_FLANG_CLAUSES_PARSER +// IMPL-NEXT: #undef GEN_FLANG_CLAUSES_PARSER +// IMPL-EMPTY: +// IMPL-NEXT: TYPE_PARSER( +// IMPL-NEXT: "clauseb" >> construct(construct(maybe(parenthesized(Parser{})))) || +// IMPL-NEXT: "clausea" >> construct(construct()) +// IMPL-NEXT: ) +// IMPL-EMPTY: +// IMPL-NEXT: #endif // GEN_FLANG_CLAUSES_PARSER +// IMPL-EMPTY: // IMPL-NEXT: #ifdef GEN_CLANG_CLAUSE_CLASS // IMPL-NEXT: #undef GEN_CLANG_CLAUSE_CLASS // IMPL-EMPTY: 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 @@ -15,6 +15,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringSet.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/TableGen/Error.h" #include "llvm/TableGen/Record.h" @@ -668,6 +669,85 @@ << " Parser clause\");\n"; } +bool compareClauseName(Record *R1, Record *R2) { + Clause C1{R1}; + Clause C2{R2}; + return (C1.getName() > C2.getName()); +} + +// Generate the parser for the clauses. +void GenerateFlangClausesParser(const DirectiveLanguage &DirLang, + raw_ostream &OS) { + std::vector Clauses = DirLang.getClauses(); + // Sort clauses in reverse alphabetical order so with clauses with same + // beginning, the longer option is tried before. + std::sort(Clauses.begin(), Clauses.end(), compareClauseName); + IfDefScope Scope("GEN_FLANG_CLAUSES_PARSER", OS); + OS << "\n"; + unsigned index = 0; + unsigned lastClauseIndex = DirLang.getClauses().size() - 1; + OS << "TYPE_PARSER(\n"; + for (const auto &C : Clauses) { + Clause Clause{C}; + if (Clause.getAliases().empty()) { + OS << " \"" << Clause.getName() << "\""; + } else { + OS << " (" + << "\"" << Clause.getName() << "\"_tok"; + for (StringRef alias : Clause.getAliases()) { + OS << " || \"" << alias << "\"_tok"; + } + OS << ")"; + } + + OS << " >> construct<" << DirLang.getFlangClauseBaseClass() + << ">(construct<" << DirLang.getFlangClauseBaseClass() + << "::" << Clause.getFormattedParserClassName() << ">("; + if (Clause.getFlangClass().empty()) { + OS << "))"; + if (index != lastClauseIndex) + OS << " ||"; + OS << "\n"; + ++index; + continue; + } + + if (Clause.isValueOptional()) + OS << "maybe("; + OS << "parenthesized("; + + if (!Clause.getPrefix().empty()) + OS << "\"" << Clause.getPrefix() << ":\" >> "; + + // The common Flang parser are used directly. Their name is identical to + // the Flang class with first letter as lowercase. If the Flang class is + // not a common class, we assume there is a specific Parser<>{} with the + // Flang class name provided. + llvm::SmallString<128> Scratch; + StringRef Parser = + llvm::StringSwitch(Clause.getFlangClass()) + .Case("Name", "name") + .Case("ScalarIntConstantExpr", "scalarIntConstantExpr") + .Case("ScalarIntExpr", "scalarIntExpr") + .Case("ScalarLogicalExpr", "scalarLogicalExpr") + .Default(("Parser<" + Clause.getFlangClass() + ">{}") + .toStringRef(Scratch)); + OS << Parser; + if (!Clause.getPrefix().empty() && Clause.isPrefixOptional()) + OS << " || " << Parser; + OS << ")"; // close parenthesized(. + + if (Clause.isValueOptional()) // close maybe(. + OS << ")"; + OS << "))"; + if (index != lastClauseIndex) + OS << " ||"; + OS << "\n"; + ++index; + } + OS << ")\n"; +} + // Generate the implementation section for the enumeration in the directive // language void EmitDirectivesFlangImpl(const DirectiveLanguage &DirLang, @@ -688,6 +768,8 @@ GenerateFlangClauseCheckPrototypes(DirLang, OS); GenerateFlangClauseParserKindMap(DirLang, OS); + + GenerateFlangClausesParser(DirLang, OS); } void GenerateClauseClassMacro(const DirectiveLanguage &DirLang,