diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h index 11725991e9c9a..49eeed0e7b439 100644 --- a/flang/include/flang/Parser/dump-parse-tree.h +++ b/flang/include/flang/Parser/dump-parse-tree.h @@ -479,7 +479,7 @@ class ParseTreeDumper { NODE(parser, OmpTraitPropertyName) NODE(parser, OmpTraitScore) NODE(parser, OmpTraitPropertyExtension) - NODE(OmpTraitPropertyExtension, ExtensionValue) + NODE(OmpTraitPropertyExtension, Complex) NODE(parser, OmpTraitProperty) NODE(parser, OmpTraitSelectorName) NODE_ENUM(OmpTraitSelectorName, Value) diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h index 00d85aa05fb3a..88ce141d17cf9 100644 --- a/flang/include/flang/Parser/parse-tree.h +++ b/flang/include/flang/Parser/parse-tree.h @@ -3505,37 +3505,22 @@ struct OmpTraitScore { }; // trait-property-extension -> -// trait-property-name (trait-property-value, ...) -// trait-property-value -> // trait-property-name | -// scalar-integer-expression | -// trait-property-extension -// -// The grammar in OpenMP 5.2+ spec is ambiguous, the above is a different -// version (but equivalent) that doesn't have ambiguities. -// The ambiguity is in -// trait-property: -// trait-property-name <- (a) -// trait-property-clause -// trait-property-expression <- (b) -// trait-property-extension <- this conflicts with (a) and (b) -// trait-property-extension: -// trait-property-name <- conflict with (a) -// identifier(trait-property-extension[, trait-property-extension[, ...]]) -// constant integer expression <- conflict with (b) +// scalar-expr | +// trait-property-name (trait-property-extension, ...) // struct OmpTraitPropertyExtension { CharBlock source; - TUPLE_CLASS_BOILERPLATE(OmpTraitPropertyExtension); - struct ExtensionValue { + UNION_CLASS_BOILERPLATE(OmpTraitPropertyExtension); + struct Complex { // name (prop-ext, prop-ext, ...) CharBlock source; - UNION_CLASS_BOILERPLATE(ExtensionValue); - std::variant> - u; + TUPLE_CLASS_BOILERPLATE(Complex); + std::tuple>> + t; }; - using ExtensionList = std::list; - std::tuple t; + + std::variant u; }; // trait-property -> @@ -3568,9 +3553,10 @@ struct OmpTraitProperty { // UID | T // unique-string-id /impl-defined // VENDOR | I // name-list (vendor-id /add-def-doc) // EXTENSION | I // name-list (ext_name /impl-defined) -// ATOMIC_DEFAULT_MEM_ORDER I | // value of admo +// ATOMIC_DEFAULT_MEM_ORDER I | // clause-list (value of admo) // REQUIRES | I // clause-list (from requires) // CONDITION U // logical-expr +// I // treated as extension // // Trait-set-selectors: // [D]evice, [T]arget_device, [C]onstruct, [I]mplementation, [U]ser. @@ -3579,7 +3565,7 @@ struct OmpTraitSelectorName { UNION_CLASS_BOILERPLATE(OmpTraitSelectorName); ENUM_CLASS(Value, Arch, Atomic_Default_Mem_Order, Condition, Device_Num, Extension, Isa, Kind, Requires, Simd, Uid, Vendor) - std::variant u; + std::variant u; }; // trait-selector -> diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp index 5ff91da082c85..30e4d4d491d58 100644 --- a/flang/lib/Parser/openmp-parsers.cpp +++ b/flang/lib/Parser/openmp-parsers.cpp @@ -158,75 +158,153 @@ static TypeDeclarationStmt makeIterSpecDecl(std::list &&names) { static std::string nameToString(Name &&name) { return name.ToString(); } TYPE_PARSER(sourced(construct( // - (space >> charLiteralConstantWithoutKind) || - applyFunction(nameToString, Parser{})))) + construct(space >> charLiteralConstantWithoutKind) || + construct( + applyFunction(nameToString, Parser{}))))) TYPE_PARSER(sourced(construct( // - "SCORE" >> parenthesized(scalarIntExpr)))) + "SCORE"_id >> parenthesized(scalarIntExpr)))) -TYPE_PARSER(sourced(construct( - // Parse nested extension first. - construct( - indirect(Parser{})) || - construct( - Parser{}) || - construct(scalarExpr)))) - -TYPE_PARSER(sourced(construct( // +TYPE_PARSER(sourced(construct( Parser{}, parenthesized(nonemptySeparated( - Parser{}, ","_tok))))) + indirect(Parser{}), ","))))) -TYPE_PARSER(sourced(construct( - // Try clause first, then extension before OmpTraitPropertyName. - construct(indirect(Parser{})) || - construct(Parser{}) || - construct(Parser{}) || - construct(scalarExpr)))) +TYPE_PARSER(sourced(construct( + construct( + Parser{}) || + construct(Parser{}) || + construct(scalarExpr)))) TYPE_PARSER(construct( - "ARCH" >> pure(OmpTraitSelectorName::Value::Arch) || - "ATOMIC_DEFAULT_MEM_ORDER" >> + "ARCH"_id >> pure(OmpTraitSelectorName::Value::Arch) || + "ATOMIC_DEFAULT_MEM_ORDER"_id >> pure(OmpTraitSelectorName::Value::Atomic_Default_Mem_Order) || - "CONDITION" >> pure(OmpTraitSelectorName::Value::Condition) || - "DEVICE_NUM" >> pure(OmpTraitSelectorName::Value::Device_Num) || - "EXTENSION" >> pure(OmpTraitSelectorName::Value::Extension) || - "ISA" >> pure(OmpTraitSelectorName::Value::Isa) || - "KIND" >> pure(OmpTraitSelectorName::Value::Kind) || - "REQUIRES" >> pure(OmpTraitSelectorName::Value::Requires) || - "SIMD" >> pure(OmpTraitSelectorName::Value::Simd) || - "UID" >> pure(OmpTraitSelectorName::Value::Uid) || - "VENDOR" >> pure(OmpTraitSelectorName::Value::Vendor))) + "CONDITION"_id >> pure(OmpTraitSelectorName::Value::Condition) || + "DEVICE_NUM"_id >> pure(OmpTraitSelectorName::Value::Device_Num) || + "EXTENSION"_id >> pure(OmpTraitSelectorName::Value::Extension) || + "ISA"_id >> pure(OmpTraitSelectorName::Value::Isa) || + "KIND"_id >> pure(OmpTraitSelectorName::Value::Kind) || + "REQUIRES"_id >> pure(OmpTraitSelectorName::Value::Requires) || + "SIMD"_id >> pure(OmpTraitSelectorName::Value::Simd) || + "UID"_id >> pure(OmpTraitSelectorName::Value::Uid) || + "VENDOR"_id >> pure(OmpTraitSelectorName::Value::Vendor))) TYPE_PARSER(sourced(construct( // Parse predefined names first (because of SIMD). construct(Parser{}) || - construct(OmpDirectiveNameParser{})))) + construct(OmpDirectiveNameParser{}) || + // identifier-or-string for extensions + construct( + applyFunction(nameToString, Parser{})) || + construct(space >> charLiteralConstantWithoutKind)))) + +// Parser for OmpTraitSelector::Properties +template +static constexpr auto propertyListParser(PropParser... pp) { + // Parse the property list "(score(expr): item1...)" in three steps: + // 1. Parse the "(" + // 2. Parse the optional "score(expr):" + // 3. Parse the "item1, ...)", together with the ")". + // The reason for including the ")" in the 3rd step is to force parsing + // the entire list in each of the alternative property parsers. Otherwise, + // the name parser could stop after "foo" in "(foo, bar(1))", without + // allowing the next parser to give the list a try. + auto listOf{[](auto parser) { // + return nonemptySeparated(parser, ","); + }}; + + using P = OmpTraitProperty; + return maybe("(" >> // + construct( + maybe(Parser{} / ":"), + (attempt(listOf(sourced(construct

(pp))) / ")") || ...))); +} + +// Parser for OmpTraitSelector +struct TraitSelectorParser { + using resultType = OmpTraitSelector; + + constexpr TraitSelectorParser(Parser p) : np(p) {} -TYPE_PARSER(construct( - maybe(Parser{} / ":"_tok), - nonemptySeparated(Parser{}, ","_tok))) + std::optional Parse(ParseState &state) const { + auto name{attempt(np).Parse(state)}; + if (!name.has_value()) { + return std::nullopt; + } + + // Default fallback parser for lists that cannot be parser using the + // primary property parser. + auto extParser{Parser{}}; + + if (auto *v{std::get_if(&name->u)}) { + // (*) The comments below show the sections of the OpenMP spec that + // describe given trait. The cases marked with a (*) are those where + // the spec doesn't assign any list-type to these traits, but for + // convenience they can be treated as if they were. + switch (*v) { + // name-list properties + case OmpTraitSelectorName::Value::Arch: // [6.0:319:18] + case OmpTraitSelectorName::Value::Extension: // [6.0:319:30] + case OmpTraitSelectorName::Value::Isa: // [6.0:319:15] + case OmpTraitSelectorName::Value::Kind: // [6.0:319:10] + case OmpTraitSelectorName::Value::Uid: // [6.0:319:23](*) + case OmpTraitSelectorName::Value::Vendor: { // [6.0:319:27] + auto pp{propertyListParser(Parser{}, extParser)}; + return OmpTraitSelector(std::move(*name), std::move(*pp.Parse(state))); + } + // clause-list + case OmpTraitSelectorName::Value::Atomic_Default_Mem_Order: + // [6.0:321:26-29](*) + case OmpTraitSelectorName::Value::Requires: // [6.0:319:33] + case OmpTraitSelectorName::Value::Simd: { // [6.0:318:31] + auto pp{propertyListParser(indirect(Parser{}), extParser)}; + return OmpTraitSelector(std::move(*name), std::move(*pp.Parse(state))); + } + // expr-list + case OmpTraitSelectorName::Value::Condition: // [6.0:321:33](*) + case OmpTraitSelectorName::Value::Device_Num: { // [6.0:321:23-24](*) + auto pp{propertyListParser(scalarExpr, extParser)}; + return OmpTraitSelector(std::move(*name), std::move(*pp.Parse(state))); + } + } // switch + } else { + // The other alternatives are `llvm::omp::Directive`, and `std::string`. + // The former doesn't take any properties[1], the latter is a name of an + // extension[2]. + // [1] [6.0:319:1-2] + // [2] [6.0:319:36-37] + auto pp{propertyListParser(extParser)}; + return OmpTraitSelector(std::move(*name), std::move(*pp.Parse(state))); + } + + llvm_unreachable("Unhandled trait name?"); + } + +private: + const Parser np; +}; -TYPE_PARSER(sourced(construct( // - Parser{}, // - maybe(parenthesized(Parser{}))))) +TYPE_PARSER(sourced(construct( + sourced(TraitSelectorParser(Parser{}))))) TYPE_PARSER(construct( - "CONSTRUCT" >> pure(OmpTraitSetSelectorName::Value::Construct) || - "DEVICE" >> pure(OmpTraitSetSelectorName::Value::Device) || - "IMPLEMENTATION" >> pure(OmpTraitSetSelectorName::Value::Implementation) || - "TARGET_DEVICE" >> pure(OmpTraitSetSelectorName::Value::Target_Device) || - "USER" >> pure(OmpTraitSetSelectorName::Value::User))) + "CONSTRUCT"_id >> pure(OmpTraitSetSelectorName::Value::Construct) || + "DEVICE"_id >> pure(OmpTraitSetSelectorName::Value::Device) || + "IMPLEMENTATION"_id >> + pure(OmpTraitSetSelectorName::Value::Implementation) || + "TARGET_DEVICE"_id >> pure(OmpTraitSetSelectorName::Value::Target_Device) || + "USER"_id >> pure(OmpTraitSetSelectorName::Value::User))) TYPE_PARSER(sourced(construct( Parser{}))) TYPE_PARSER(sourced(construct( // Parser{}, - "=" >> braced(nonemptySeparated(Parser{}, ","_tok))))) + "=" >> braced(nonemptySeparated(Parser{}, ","))))) TYPE_PARSER(sourced(construct( - nonemptySeparated(Parser{}, ","_tok)))) + nonemptySeparated(Parser{}, ",")))) // Parser == Parser diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp index 7bf404bba2c3e..af5259e1daec4 100644 --- a/flang/lib/Parser/unparse.cpp +++ b/flang/lib/Parser/unparse.cpp @@ -2075,10 +2075,11 @@ class UnparseVisitor { Walk(x.v); Put(")"); } - void Unparse(const OmpTraitPropertyExtension &x) { + void Unparse(const OmpTraitPropertyExtension::Complex &x) { + using PropList = std::list>; Walk(std::get(x.t)); Put("("); - Walk(std::get(x.t), ","); + Walk(std::get(x.t), ","); Put(")"); } void Unparse(const OmpTraitSelector &x) {