From fa9b23d9bd669f2447b1594ec845752ff84dad1b Mon Sep 17 00:00:00 2001 From: Krzysztof Parzyszek Date: Thu, 12 Dec 2024 15:09:49 -0600 Subject: [PATCH 1/8] [flang][Parser] Convert applyMem to invoke non-void members Currently applyMem(f, a, ...) calls a.f(...), but still returns the result of parser a. This is in contrast to applyFunction(f, a, ...), which returns the result of calling f(a, ...). The use case for this is being able to parse quoted or unquoted strings, and store the result as std::string: ``` construct( (space >> charLiteralConstantWithoutKind) || applyMem(&Name::ToString, Parser{})) // Parser{}.ToString() ``` The applyMem combinator is currently unused. --- flang/docs/ParserCombinators.md | 2 +- flang/lib/Parser/basic-parsers.h | 54 ++++++++++++++------------------ 2 files changed, 24 insertions(+), 32 deletions(-) diff --git a/flang/docs/ParserCombinators.md b/flang/docs/ParserCombinators.md index 7cb77deba2197..076e76f703c49 100644 --- a/flang/docs/ParserCombinators.md +++ b/flang/docs/ParserCombinators.md @@ -141,7 +141,7 @@ collect the values that they return. * `applyLambda([](&&x){}, p1, p2, ...)` is the same thing, but for lambdas and other function objects. * `applyMem(mf, p1, p2, ...)` is the same thing, but invokes a member - function of the result of the first parser for updates in place. + function of the result of the first parser. ### Token Parsers Last, we have these basic parsers on which the actual grammar of the Fortran diff --git a/flang/lib/Parser/basic-parsers.h b/flang/lib/Parser/basic-parsers.h index 515b5993d6737..1a8c14e7048f6 100644 --- a/flang/lib/Parser/basic-parsers.h +++ b/flang/lib/Parser/basic-parsers.h @@ -580,11 +580,11 @@ template inline constexpr auto defaulted(PA p) { // applyLambda(f, ...) is the same concept extended to std::function<> functors. // It is not constexpr. // -// Member function application is supported by applyMem(f, a). If the -// parser a succeeds and returns some value ax, the result is that returned -// by ax.f(). Additional parser arguments can be specified to supply their -// results to the member function call, so applyMem(f, a, b) succeeds if -// both a and b do so and returns the result of calling ax.f(std::move(bx)). +// Member function application is supported by applyMem(&C::f, a). If the +// parser a succeeds and returns some value ax of type C, the result is that +// returned by ax.f(). Additional parser arguments can be specified to supply +// their results to the member function call, so applyMem(&C::f, a, b) succeeds +// if both a and b do so and returns the result of calling ax.f(std::move(bx)). // Runs a sequence of parsers until one fails or all have succeeded. // Collects their results in a std::tuple...>. @@ -654,39 +654,31 @@ inline /* not constexpr */ auto applyLambda( } // Member function application -template class AMFPHelper { - using resultType = typename OBJPARSER::resultType; - -public: - using type = void (resultType::*)(typename PARSER::resultType &&...); -}; -template -using ApplicableMemberFunctionPointer = - typename AMFPHelper::type; - -template -inline auto ApplyHelperMember( - ApplicableMemberFunctionPointer mfp, - ApplyArgs &&args, std::index_sequence) -> - typename OBJPARSER::resultType { - ((*std::get<0>(args)).*mfp)(std::move(*std::get(args))...); - return std::get<0>(std::move(args)); +template +inline auto ApplyHelperMember(MEMFUNC mfp, + ApplyArgs &&args, std::index_sequence) { + return ((*std::get<0>(args)).*mfp)(std::move(*std::get(args))...); } -template class ApplyMemberFunction { - using funcType = ApplicableMemberFunctionPointer; +template +class ApplyMemberFunction { + static_assert(std::is_member_function_pointer_v); + using funcType = MEMFUNC; public: - using resultType = typename OBJPARSER::resultType; + using resultType = + std::invoke_result_t; + constexpr ApplyMemberFunction(const ApplyMemberFunction &) = default; - constexpr ApplyMemberFunction(funcType f, OBJPARSER o, PARSER... p) + constexpr ApplyMemberFunction(MEMFUNC f, OBJPARSER o, PARSER... p) : function_{f}, parsers_{o, p...} {} std::optional Parse(ParseState &state) const { ApplyArgs results; using Sequence1 = std::index_sequence_for; using Sequence2 = std::index_sequence_for; if (ApplyHelperArgs(parsers_, results, state, Sequence1{})) { - return ApplyHelperMember( + return ApplyHelperMember( function_, std::move(results), Sequence2{}); } else { return std::nullopt; @@ -698,11 +690,11 @@ template class ApplyMemberFunction { const std::tuple parsers_; }; -template +template inline constexpr auto applyMem( - ApplicableMemberFunctionPointer mfp, - const OBJPARSER &objParser, PARSER... parser) { - return ApplyMemberFunction{mfp, objParser, parser...}; + MEMFUNC memfn, const OBJPARSER &objParser, PARSER... parser) { + return ApplyMemberFunction{ + memfn, objParser, parser...}; } // As is done with function application via applyFunction() above, class From 215c7e6133bf07d005ac7483b8faf797e319a1fa Mon Sep 17 00:00:00 2001 From: Krzysztof Parzyszek Date: Thu, 12 Dec 2024 15:26:26 -0600 Subject: [PATCH 2/8] [flang][OpenMP] Parsing context selectors for METADIRECTIVE This is just adding parsers for context selectors. There are no tests because there is no way to execute these parsers yet. --- flang/include/flang/Parser/characters.h | 2 + flang/include/flang/Parser/dump-parse-tree.h | 14 ++ flang/include/flang/Parser/parse-tree.h | 136 +++++++++++++++++++ flang/lib/Parser/openmp-parsers.cpp | 78 +++++++++++ flang/lib/Parser/token-parsers.h | 4 + flang/lib/Parser/unparse.cpp | 38 ++++++ flang/lib/Semantics/check-omp-structure.cpp | 8 ++ flang/lib/Semantics/check-omp-structure.h | 3 + flang/lib/Semantics/resolve-directives.cpp | 6 + 9 files changed, 289 insertions(+) diff --git a/flang/include/flang/Parser/characters.h b/flang/include/flang/Parser/characters.h index df188d674b9ee..dbdc058c44995 100644 --- a/flang/include/flang/Parser/characters.h +++ b/flang/include/flang/Parser/characters.h @@ -180,6 +180,8 @@ inline constexpr bool IsValidFortranTokenCharacter(char ch) { case '>': case '[': case ']': + case '{': // Used in OpenMP context selector specification + case '}': // return true; default: return IsLegalIdentifierStart(ch) || IsDecimalDigit(ch); diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h index 3331520922bc6..a61d7973dd5c3 100644 --- a/flang/include/flang/Parser/dump-parse-tree.h +++ b/flang/include/flang/Parser/dump-parse-tree.h @@ -476,6 +476,20 @@ class ParseTreeDumper { NODE(parser, NullInit) NODE(parser, ObjectDecl) NODE(parser, OldParameterStmt) + NODE(parser, OmpDirectiveSpecification) + NODE(parser, OmpTraitPropertyName) + NODE(parser, OmpTraitScore) + NODE(parser, OmpTraitPropertyExtension) + NODE(OmpTraitPropertyExtension, ExtensionValue) + NODE(parser, OmpTraitProperty) + NODE(parser, OmpTraitSelectorName) + NODE_ENUM(OmpTraitSelectorName, Value) + NODE(parser, OmpTraitSelector) + NODE(OmpTraitSelector, Properties) + NODE(parser, OmpTraitSetSelectorName) + NODE_ENUM(OmpTraitSetSelectorName, Value) + NODE(parser, OmpTraitSetSelector) + NODE(parser, OmpContextSelectorSpecification) NODE(parser, OmpMapper) NODE(parser, OmpMapType) NODE_ENUM(OmpMapType, Value) diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h index 941d70d387629..697bddfaf1615 100644 --- a/flang/include/flang/Parser/parse-tree.h +++ b/flang/include/flang/Parser/parse-tree.h @@ -3453,6 +3453,17 @@ WRAPPER_CLASS(PauseStmt, std::optional); // --- Common definitions +struct OmpClause; +struct OmpClauseList; + +struct OmpDirectiveSpecification { + TUPLE_CLASS_BOILERPLATE(OmpDirectiveSpecification); + std::tuple>> + t; + CharBlock source; +}; + // 2.1 Directives or clauses may accept a list or extended-list. // A list item is a variable, array section or common block name (enclosed // in slashes). An extended list item is a list item or a procedure Name. @@ -3474,6 +3485,128 @@ WRAPPER_CLASS(OmpObjectList, std::list); #define MODIFIERS() std::optional> +inline namespace traits { +// trait-property-name -> +// identifier | string-literal +struct OmpTraitPropertyName { + WRAPPER_CLASS_BOILERPLATE(OmpTraitPropertyName, std::string); +}; + +// trait-score -> +// SCORE(non-negative-const-integer-expression) +struct OmpTraitScore { + WRAPPER_CLASS_BOILERPLATE(OmpTraitScore, ScalarIntExpr); +}; + +// 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) +// +struct OmpTraitPropertyExtension { + TUPLE_CLASS_BOILERPLATE(OmpTraitPropertyExtension); + struct ExtensionValue { + UNION_CLASS_BOILERPLATE(ExtensionValue); + std::variant> + u; + }; + using ExtensionList = std::list; + std::tuple t; +}; + +// trait-property -> +// trait-property-name | OmpClause | +// trait-property-expression | trait-property-extension +// trait-property-expression -> +// scalar-logical-expression | scalar-integer-expression +// +// The parser for a logical expression will accept an integer expression, +// and if it's not logical, it will flag an error later. The same thing +// will happen if the scalar integer expression sees a logical expresion. +// To avoid this, parse all expressions as scalar expressions. +struct OmpTraitProperty { + UNION_CLASS_BOILERPLATE(OmpTraitProperty); + std::variant, + ScalarExpr, // trait-property-expresion + OmpTraitPropertyExtension> + u; +}; + +// trait-selector-name -> +// KIND | DT // name-list (host, nohost, +/add-def-doc) +// ISA | DT // name-list (isa_name, ... /impl-defined) +// ARCH | DT // name-list (arch_name, ... /impl-defined) +// directive-name | C // no properties +// SIMD | C // clause-list (from declare_simd) +// // (at least simdlen, inbranch/notinbranch) +// DEVICE_NUM | T // device-number +// 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 +// REQUIRES | I // clause-list (from requires) +// CONDITION U // logical-expr +// +// Trait-set-selectors: +// [D]evice, [T]arget_device, [C]onstruct, [I]mplementation, [U]ser. +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; +}; + +// trait-selector -> +// trait-selector-name | +// trait-selector-name ([trait-score:] trait-property, ...) +struct OmpTraitSelector { + TUPLE_CLASS_BOILERPLATE(OmpTraitSelector); + struct Properties { + TUPLE_CLASS_BOILERPLATE(Properties); + std::tuple, std::list> t; + }; + std::tuple> t; +}; + +// trait-set-selector-name -> +// CONSTRUCT | DEVICE | IMPLEMENTATION | USER | // since 5.0 +// TARGET_DEVICE // since 5.1 +struct OmpTraitSetSelectorName { + ENUM_CLASS(Value, Construct, Device, Implementation, Target_Device, User) + WRAPPER_CLASS_BOILERPLATE(OmpTraitSetSelectorName, Value); +}; + +// trait-set-selector -> +// trait-set-selector-name = {trait-selector, ...} +struct OmpTraitSetSelector { + TUPLE_CLASS_BOILERPLATE(OmpTraitSetSelector); + std::tuple> t; +}; + +// context-selector-specification -> +// trait-set-selector, ... +struct OmpContextSelectorSpecification { // Modifier + WRAPPER_CLASS_BOILERPLATE( + OmpContextSelectorSpecification, std::list); +}; +} // namespace traits + inline namespace modifier { // For uniformity, in all keyword modifiers the name of the type defined // by ENUM_CLASS is "Value", e.g. @@ -3744,6 +3877,9 @@ struct OmpVariableCategory { ENUM_CLASS(Value, Aggregate, All, Allocatable, Pointer, Scalar) WRAPPER_CLASS_BOILERPLATE(OmpVariableCategory, Value); }; + +// context-selector +using OmpContextSelector = traits::OmpContextSelectorSpecification; } // namespace modifier // --- Clauses diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp index 894c458a335b2..35ed32602ecc9 100644 --- a/flang/lib/Parser/openmp-parsers.cpp +++ b/flang/lib/Parser/openmp-parsers.cpp @@ -153,6 +153,84 @@ static TypeDeclarationStmt makeIterSpecDecl(std::list &&names) { makeEntityList(std::move(names))); } +TYPE_PARSER(sourced(construct( + OmpDirectiveNameParser{}, maybe(indirect(Parser{}))))) + +// --- Parsers for context traits ------------------------------------- + +TYPE_PARSER(construct( // + (space >> charLiteralConstantWithoutKind) || + applyMem(&Name::ToString, Parser{}))) + +TYPE_PARSER(construct( // + "SCORE" >> parenthesized(scalarIntExpr))) + +TYPE_PARSER(construct( + // Parse nested extension first. + construct( + indirect(Parser{})) || + construct( + Parser{}) || + construct(scalarExpr))) + +TYPE_PARSER(construct( // + Parser{}, + parenthesized(nonemptySeparated( + Parser{}, ","_tok)))) + +TYPE_PARSER(construct( + // Try extension first, before OmpTraitPropertyName. + construct(Parser{}) || + construct(Parser{}) || + construct(indirect(Parser{})) || + construct(scalarExpr))) + +TYPE_PARSER(construct( + "ARCH" >> pure(OmpTraitSelectorName::Value::Arch) || + "ATOMIC_DEFAULT_MEM_ORDER" >> + 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))) + +TYPE_PARSER(construct( + // Parse predefined names first (because of SIMD). + construct(Parser{}) || + construct(OmpDirectiveNameParser{}))) + +TYPE_PARSER(construct( + maybe(Parser{} / ":"_tok), + nonemptySeparated(Parser{}, ","_tok))) + +TYPE_PARSER(construct( // + Parser{}, // + maybe(parenthesized(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))) + +TYPE_PARSER(construct( + Parser{})) + +TYPE_PARSER(construct( // + Parser{}, + "=" >> braced(nonemptySeparated(Parser{}, ","_tok)))) + +TYPE_PARSER(construct( + nonemptySeparated(Parser{}, ","_tok))) + +// Parser == Parser + // --- Parsers for clause modifiers ----------------------------------- TYPE_PARSER(construct(scalarIntExpr)) diff --git a/flang/lib/Parser/token-parsers.h b/flang/lib/Parser/token-parsers.h index fe6bc1f69f576..3e0c59b89d964 100644 --- a/flang/lib/Parser/token-parsers.h +++ b/flang/lib/Parser/token-parsers.h @@ -215,6 +215,10 @@ template inline constexpr auto bracketed(const PA &p) { return "[" >> p / "]"; } +template inline constexpr auto braced(const PA &p) { + return "{" >> p / "}"; +} + // Quoted character literal constants. struct CharLiteralChar { using resultType = std::pair; diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp index 58820476c51bc..31a2c3bbc408d 100644 --- a/flang/lib/Parser/unparse.cpp +++ b/flang/lib/Parser/unparse.cpp @@ -2067,6 +2067,41 @@ class UnparseVisitor { } // OpenMP Clauses & Directives + void Unparse(const llvm::omp::Directive &x) { + Word(llvm::omp::getOpenMPDirectiveName(x).str()); + } + void Unparse(const OmpDirectiveSpecification &x) { + Walk(std::get(x.t)); + Walk(std::get>>(x.t)); + } + void Unparse(const OmpTraitScore &x) { + Word("SCORE("); + Walk(x.v); + Put(")"); + } + void Unparse(const OmpTraitPropertyExtension &x) { + Walk(std::get(x.t)); + Put("("); + Walk(std::get(x.t), ","); + Put(")"); + } + void Unparse(const OmpTraitSelector &x) { + Walk(std::get(x.t)); + Walk(std::get>(x.t)); + } + void Unparse(const OmpTraitSelector::Properties &x) { + Put("("); + Walk(std::get>(x.t), ": "); + Walk(std::get>(x.t)); + Put(")"); + } + void Unparse(const OmpTraitSetSelector &x) { + Walk(std::get(x.t)); + Put("={"); + Walk(std::get>(x.t)); + Put("}"); + } + void Unparse(const OmpObject &x) { common::visit(common::visitors{ [&](const Designator &y) { Walk(y); }, @@ -2916,6 +2951,9 @@ class UnparseVisitor { WALK_NESTED_ENUM(OmpPrescriptiveness, Value) // OMP prescriptiveness WALK_NESTED_ENUM(OmpMapType, Value) // OMP map-type WALK_NESTED_ENUM(OmpMapTypeModifier, Value) // OMP map-type-modifier + WALK_NESTED_ENUM(OmpTraitSelectorName, Value) + WALK_NESTED_ENUM(OmpTraitSetSelectorName, Value) + #undef WALK_NESTED_ENUM void Unparse(const ReductionOperator::Operator x) { switch (x) { diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp index 6db43cf6f04bd..67f7f65b7e422 100644 --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -590,6 +590,14 @@ void OmpStructureChecker::CheckHintClause( } } +void OmpStructureChecker::Enter(const parser::OmpDirectiveSpecification &x) { + PushContextAndClauseSets(x.source, std::get(x.t)); +} + +void OmpStructureChecker::Leave(const parser::OmpDirectiveSpecification &) { + dirContext_.pop_back(); +} + void OmpStructureChecker::Enter(const parser::OpenMPConstruct &x) { // Simd Construct with Ordered Construct Nesting check // We cannot use CurrentDirectiveIsNested() here because diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h index dc360957c873b..1fc7e6c1e9baa 100644 --- a/flang/lib/Semantics/check-omp-structure.h +++ b/flang/lib/Semantics/check-omp-structure.h @@ -144,6 +144,9 @@ class OmpStructureChecker void Enter(const parser::DoConstruct &); void Leave(const parser::DoConstruct &); + void Enter(const parser::OmpDirectiveSpecification &); + void Leave(const parser::OmpDirectiveSpecification &); + #define GEN_FLANG_CLAUSE_CHECK_ENTER #include "llvm/Frontend/OpenMP/OMP.inc" diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp index 39478b58a9070..4e423ea1b4325 100644 --- a/flang/lib/Semantics/resolve-directives.cpp +++ b/flang/lib/Semantics/resolve-directives.cpp @@ -351,6 +351,12 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor { return true; } + bool Pre(const parser::OmpDirectiveSpecification &x) { + PushContext(x.source, std::get(x.t)); + return true; + } + void Post(const parser::OmpDirectiveSpecification &) { PopContext(); } + bool Pre(const parser::OpenMPBlockConstruct &); void Post(const parser::OpenMPBlockConstruct &); From 0e317db2f2bbc24f0c3b427031cb26ba4daf9e6e Mon Sep 17 00:00:00 2001 From: Krzysztof Parzyszek Date: Thu, 9 Jan 2025 09:22:59 -0600 Subject: [PATCH 3/8] Remove DirectiveSpecification --- flang/include/flang/Parser/dump-parse-tree.h | 1 - flang/include/flang/Parser/parse-tree.h | 8 -------- flang/lib/Parser/openmp-parsers.cpp | 3 --- flang/lib/Parser/unparse.cpp | 4 ---- flang/lib/Semantics/check-omp-structure.cpp | 8 -------- flang/lib/Semantics/check-omp-structure.h | 3 --- flang/lib/Semantics/resolve-directives.cpp | 6 ------ 7 files changed, 33 deletions(-) diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h index a61d7973dd5c3..11725991e9c9a 100644 --- a/flang/include/flang/Parser/dump-parse-tree.h +++ b/flang/include/flang/Parser/dump-parse-tree.h @@ -476,7 +476,6 @@ class ParseTreeDumper { NODE(parser, NullInit) NODE(parser, ObjectDecl) NODE(parser, OldParameterStmt) - NODE(parser, OmpDirectiveSpecification) NODE(parser, OmpTraitPropertyName) NODE(parser, OmpTraitScore) NODE(parser, OmpTraitPropertyExtension) diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h index 697bddfaf1615..fbe0ff39f4079 100644 --- a/flang/include/flang/Parser/parse-tree.h +++ b/flang/include/flang/Parser/parse-tree.h @@ -3456,14 +3456,6 @@ WRAPPER_CLASS(PauseStmt, std::optional); struct OmpClause; struct OmpClauseList; -struct OmpDirectiveSpecification { - TUPLE_CLASS_BOILERPLATE(OmpDirectiveSpecification); - std::tuple>> - t; - CharBlock source; -}; - // 2.1 Directives or clauses may accept a list or extended-list. // A list item is a variable, array section or common block name (enclosed // in slashes). An extended list item is a list item or a procedure Name. diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp index 35ed32602ecc9..ca9a2caf56fd7 100644 --- a/flang/lib/Parser/openmp-parsers.cpp +++ b/flang/lib/Parser/openmp-parsers.cpp @@ -153,9 +153,6 @@ static TypeDeclarationStmt makeIterSpecDecl(std::list &&names) { makeEntityList(std::move(names))); } -TYPE_PARSER(sourced(construct( - OmpDirectiveNameParser{}, maybe(indirect(Parser{}))))) - // --- Parsers for context traits ------------------------------------- TYPE_PARSER(construct( // diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp index 31a2c3bbc408d..ddd20ddeb4302 100644 --- a/flang/lib/Parser/unparse.cpp +++ b/flang/lib/Parser/unparse.cpp @@ -2070,10 +2070,6 @@ class UnparseVisitor { void Unparse(const llvm::omp::Directive &x) { Word(llvm::omp::getOpenMPDirectiveName(x).str()); } - void Unparse(const OmpDirectiveSpecification &x) { - Walk(std::get(x.t)); - Walk(std::get>>(x.t)); - } void Unparse(const OmpTraitScore &x) { Word("SCORE("); Walk(x.v); diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp index 67f7f65b7e422..6db43cf6f04bd 100644 --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -590,14 +590,6 @@ void OmpStructureChecker::CheckHintClause( } } -void OmpStructureChecker::Enter(const parser::OmpDirectiveSpecification &x) { - PushContextAndClauseSets(x.source, std::get(x.t)); -} - -void OmpStructureChecker::Leave(const parser::OmpDirectiveSpecification &) { - dirContext_.pop_back(); -} - void OmpStructureChecker::Enter(const parser::OpenMPConstruct &x) { // Simd Construct with Ordered Construct Nesting check // We cannot use CurrentDirectiveIsNested() here because diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h index 1fc7e6c1e9baa..dc360957c873b 100644 --- a/flang/lib/Semantics/check-omp-structure.h +++ b/flang/lib/Semantics/check-omp-structure.h @@ -144,9 +144,6 @@ class OmpStructureChecker void Enter(const parser::DoConstruct &); void Leave(const parser::DoConstruct &); - void Enter(const parser::OmpDirectiveSpecification &); - void Leave(const parser::OmpDirectiveSpecification &); - #define GEN_FLANG_CLAUSE_CHECK_ENTER #include "llvm/Frontend/OpenMP/OMP.inc" diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp index 4e423ea1b4325..39478b58a9070 100644 --- a/flang/lib/Semantics/resolve-directives.cpp +++ b/flang/lib/Semantics/resolve-directives.cpp @@ -351,12 +351,6 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor { return true; } - bool Pre(const parser::OmpDirectiveSpecification &x) { - PushContext(x.source, std::get(x.t)); - return true; - } - void Post(const parser::OmpDirectiveSpecification &) { PopContext(); } - bool Pre(const parser::OpenMPBlockConstruct &); void Post(const parser::OpenMPBlockConstruct &); From 419bdfa27ef1ed3ca3a46cf8601c2536e091ba85 Mon Sep 17 00:00:00 2001 From: Krzysztof Parzyszek Date: Tue, 7 Jan 2025 14:47:15 -0600 Subject: [PATCH 4/8] Fix unparsing multiple set selectors --- flang/lib/Parser/unparse.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp index ddd20ddeb4302..7bf404bba2c3e 100644 --- a/flang/lib/Parser/unparse.cpp +++ b/flang/lib/Parser/unparse.cpp @@ -2097,6 +2097,7 @@ class UnparseVisitor { Walk(std::get>(x.t)); Put("}"); } + void Unparse(const OmpContextSelectorSpecification &x) { Walk(x.v, ", "); } void Unparse(const OmpObject &x) { common::visit(common::visitors{ From c4b900779d1f132ba2f50f592fbffe15e2ff0c3b Mon Sep 17 00:00:00 2001 From: Krzysztof Parzyszek Date: Thu, 9 Jan 2025 10:15:41 -0600 Subject: [PATCH 5/8] Add "source" to context objects --- flang/include/flang/Parser/parse-tree.h | 10 +++++++ flang/lib/Parser/openmp-parsers.cpp | 40 ++++++++++++------------- 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h index fbe0ff39f4079..1d4d5a820249c 100644 --- a/flang/include/flang/Parser/parse-tree.h +++ b/flang/include/flang/Parser/parse-tree.h @@ -3481,12 +3481,14 @@ inline namespace traits { // trait-property-name -> // identifier | string-literal struct OmpTraitPropertyName { + CharBlock source; WRAPPER_CLASS_BOILERPLATE(OmpTraitPropertyName, std::string); }; // trait-score -> // SCORE(non-negative-const-integer-expression) struct OmpTraitScore { + CharBlock source; WRAPPER_CLASS_BOILERPLATE(OmpTraitScore, ScalarIntExpr); }; @@ -3511,8 +3513,10 @@ struct OmpTraitScore { // constant integer expression <- conflict with (b) // struct OmpTraitPropertyExtension { + CharBlock source; TUPLE_CLASS_BOILERPLATE(OmpTraitPropertyExtension); struct ExtensionValue { + CharBlock source; UNION_CLASS_BOILERPLATE(ExtensionValue); std::variant> @@ -3533,6 +3537,7 @@ struct OmpTraitPropertyExtension { // will happen if the scalar integer expression sees a logical expresion. // To avoid this, parse all expressions as scalar expressions. struct OmpTraitProperty { + CharBlock source; UNION_CLASS_BOILERPLATE(OmpTraitProperty); std::variant, ScalarExpr, // trait-property-expresion @@ -3558,6 +3563,7 @@ struct OmpTraitProperty { // Trait-set-selectors: // [D]evice, [T]arget_device, [C]onstruct, [I]mplementation, [U]ser. struct OmpTraitSelectorName { + CharBlock source; UNION_CLASS_BOILERPLATE(OmpTraitSelectorName); ENUM_CLASS(Value, Arch, Atomic_Default_Mem_Order, Condition, Device_Num, Extension, Isa, Kind, Requires, Simd, Uid, Vendor) @@ -3568,6 +3574,7 @@ struct OmpTraitSelectorName { // trait-selector-name | // trait-selector-name ([trait-score:] trait-property, ...) struct OmpTraitSelector { + CharBlock source; TUPLE_CLASS_BOILERPLATE(OmpTraitSelector); struct Properties { TUPLE_CLASS_BOILERPLATE(Properties); @@ -3580,6 +3587,7 @@ struct OmpTraitSelector { // CONSTRUCT | DEVICE | IMPLEMENTATION | USER | // since 5.0 // TARGET_DEVICE // since 5.1 struct OmpTraitSetSelectorName { + CharBlock source; ENUM_CLASS(Value, Construct, Device, Implementation, Target_Device, User) WRAPPER_CLASS_BOILERPLATE(OmpTraitSetSelectorName, Value); }; @@ -3587,6 +3595,7 @@ struct OmpTraitSetSelectorName { // trait-set-selector -> // trait-set-selector-name = {trait-selector, ...} struct OmpTraitSetSelector { + CharBlock source; TUPLE_CLASS_BOILERPLATE(OmpTraitSetSelector); std::tuple> t; }; @@ -3594,6 +3603,7 @@ struct OmpTraitSetSelector { // context-selector-specification -> // trait-set-selector, ... struct OmpContextSelectorSpecification { // Modifier + CharBlock source; WRAPPER_CLASS_BOILERPLATE( OmpContextSelectorSpecification, std::list); }; diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp index ca9a2caf56fd7..7f7eaaeaef635 100644 --- a/flang/lib/Parser/openmp-parsers.cpp +++ b/flang/lib/Parser/openmp-parsers.cpp @@ -155,32 +155,32 @@ static TypeDeclarationStmt makeIterSpecDecl(std::list &&names) { // --- Parsers for context traits ------------------------------------- -TYPE_PARSER(construct( // +TYPE_PARSER(sourced(construct( // (space >> charLiteralConstantWithoutKind) || - applyMem(&Name::ToString, Parser{}))) + applyMem(&Name::ToString, Parser{})))) -TYPE_PARSER(construct( // - "SCORE" >> parenthesized(scalarIntExpr))) +TYPE_PARSER(sourced(construct( // + "SCORE" >> parenthesized(scalarIntExpr)))) -TYPE_PARSER(construct( +TYPE_PARSER(sourced(construct( // Parse nested extension first. construct( indirect(Parser{})) || construct( Parser{}) || - construct(scalarExpr))) + construct(scalarExpr)))) -TYPE_PARSER(construct( // +TYPE_PARSER(sourced(construct( // Parser{}, parenthesized(nonemptySeparated( - Parser{}, ","_tok)))) + Parser{}, ","_tok))))) -TYPE_PARSER(construct( +TYPE_PARSER(sourced(construct( // Try extension first, before OmpTraitPropertyName. construct(Parser{}) || construct(Parser{}) || construct(indirect(Parser{})) || - construct(scalarExpr))) + construct(scalarExpr)))) TYPE_PARSER(construct( "ARCH" >> pure(OmpTraitSelectorName::Value::Arch) || @@ -196,18 +196,18 @@ TYPE_PARSER(construct( "UID" >> pure(OmpTraitSelectorName::Value::Uid) || "VENDOR" >> pure(OmpTraitSelectorName::Value::Vendor))) -TYPE_PARSER(construct( +TYPE_PARSER(sourced(construct( // Parse predefined names first (because of SIMD). construct(Parser{}) || - construct(OmpDirectiveNameParser{}))) + construct(OmpDirectiveNameParser{})))) TYPE_PARSER(construct( maybe(Parser{} / ":"_tok), nonemptySeparated(Parser{}, ","_tok))) -TYPE_PARSER(construct( // +TYPE_PARSER(sourced(construct( // Parser{}, // - maybe(parenthesized(Parser{})))) + maybe(parenthesized(Parser{}))))) TYPE_PARSER(construct( "CONSTRUCT" >> pure(OmpTraitSetSelectorName::Value::Construct) || @@ -216,15 +216,15 @@ TYPE_PARSER(construct( "TARGET_DEVICE" >> pure(OmpTraitSetSelectorName::Value::Target_Device) || "USER" >> pure(OmpTraitSetSelectorName::Value::User))) -TYPE_PARSER(construct( - Parser{})) +TYPE_PARSER(sourced(construct( + Parser{}))) -TYPE_PARSER(construct( // +TYPE_PARSER(sourced(construct( // Parser{}, - "=" >> braced(nonemptySeparated(Parser{}, ","_tok)))) + "=" >> braced(nonemptySeparated(Parser{}, ","_tok))))) -TYPE_PARSER(construct( - nonemptySeparated(Parser{}, ","_tok))) +TYPE_PARSER(sourced(construct( + nonemptySeparated(Parser{}, ","_tok)))) // Parser == Parser From d6ca30be75a54d0fe2b9f56e9494ad6bab25a479 Mon Sep 17 00:00:00 2001 From: Krzysztof Parzyszek Date: Thu, 9 Jan 2025 10:23:26 -0600 Subject: [PATCH 6/8] Try clause first when parsing trait --- flang/lib/Parser/openmp-parsers.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp index 7f7eaaeaef635..44db56165452c 100644 --- a/flang/lib/Parser/openmp-parsers.cpp +++ b/flang/lib/Parser/openmp-parsers.cpp @@ -176,10 +176,10 @@ TYPE_PARSER(sourced(construct( // Parser{}, ","_tok))))) TYPE_PARSER(sourced(construct( - // Try extension first, before OmpTraitPropertyName. + // Try clause first, then extension before OmpTraitPropertyName. + construct(indirect(Parser{})) || construct(Parser{}) || construct(Parser{}) || - construct(indirect(Parser{})) || construct(scalarExpr)))) TYPE_PARSER(construct( From e0ca3474881b4a64247c87605a4d2bbeacc94c2d Mon Sep 17 00:00:00 2001 From: Krzysztof Parzyszek Date: Fri, 10 Jan 2025 09:24:14 -0600 Subject: [PATCH 7/8] add comment with explanation --- flang/include/flang/Parser/parse-tree.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h index 1d4d5a820249c..00d85aa05fb3a 100644 --- a/flang/include/flang/Parser/parse-tree.h +++ b/flang/include/flang/Parser/parse-tree.h @@ -3480,6 +3480,18 @@ WRAPPER_CLASS(OmpObjectList, std::list); inline namespace traits { // trait-property-name -> // identifier | string-literal +// +// This is a bit of a problematic case. The spec says that a word in quotes, +// and the same word without quotes are equivalent. We currently parse both +// as a string, but it's likely just a temporary solution. +// +// The problem is that trait-property can be (among other things) a +// trait-property-name or a trait-property-expression. A simple identifier +// can be either, there is no reasonably simple way of telling them apart +// in the parser. There is a similar issue with extensions. Some of that +// disambiguation may need to be done in the "canonicalization" pass and +// then some of those AST nodes would be rewritten into different ones. +// struct OmpTraitPropertyName { CharBlock source; WRAPPER_CLASS_BOILERPLATE(OmpTraitPropertyName, std::string); From ca7584b5432b2e8351d1f2ab50c830377b2f1478 Mon Sep 17 00:00:00 2001 From: Krzysztof Parzyszek Date: Fri, 10 Jan 2025 09:38:31 -0600 Subject: [PATCH 8/8] remove use of applyMem --- flang/lib/Parser/openmp-parsers.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp index 44db56165452c..5ff91da082c85 100644 --- a/flang/lib/Parser/openmp-parsers.cpp +++ b/flang/lib/Parser/openmp-parsers.cpp @@ -155,9 +155,11 @@ static TypeDeclarationStmt makeIterSpecDecl(std::list &&names) { // --- Parsers for context traits ------------------------------------- +static std::string nameToString(Name &&name) { return name.ToString(); } + TYPE_PARSER(sourced(construct( // (space >> charLiteralConstantWithoutKind) || - applyMem(&Name::ToString, Parser{})))) + applyFunction(nameToString, Parser{})))) TYPE_PARSER(sourced(construct( // "SCORE" >> parenthesized(scalarIntExpr))))