https://github.com/kparzysz updated https://github.com/llvm/llvm-project/pull/121815
>From 215c7e6133bf07d005ac7483b8faf797e319a1fa Mon Sep 17 00:00:00 2001 From: Krzysztof Parzyszek <krzysztof.parzys...@amd.com> Date: Thu, 12 Dec 2024 15:26:26 -0600 Subject: [PATCH] [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 df188d674b9eeb..dbdc058c44995a 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 3331520922bc63..a61d7973dd5c36 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 941d70d3876291..697bddfaf16150 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<StopCode>); // --- Common definitions +struct OmpClause; +struct OmpClauseList; + +struct OmpDirectiveSpecification { + TUPLE_CLASS_BOILERPLATE(OmpDirectiveSpecification); + std::tuple<llvm::omp::Directive, + std::optional<common::Indirection<OmpClauseList>>> + 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<OmpObject>); #define MODIFIERS() std::optional<std::list<Modifier>> +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<OmpTraitPropertyName, ScalarExpr, + common::Indirection<OmpTraitPropertyExtension>> + u; + }; + using ExtensionList = std::list<ExtensionValue>; + std::tuple<OmpTraitPropertyName, ExtensionList> 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<OmpTraitPropertyName, common::Indirection<OmpClause>, + 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<Value, llvm::omp::Directive> 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::optional<OmpTraitScore>, std::list<OmpTraitProperty>> t; + }; + std::tuple<OmpTraitSelectorName, std::optional<Properties>> 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<OmpTraitSetSelectorName, std::list<OmpTraitSelector>> t; +}; + +// context-selector-specification -> +// trait-set-selector, ... +struct OmpContextSelectorSpecification { // Modifier + WRAPPER_CLASS_BOILERPLATE( + OmpContextSelectorSpecification, std::list<OmpTraitSetSelector>); +}; +} // 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 894c458a335b27..35ed32602ecc94 100644 --- a/flang/lib/Parser/openmp-parsers.cpp +++ b/flang/lib/Parser/openmp-parsers.cpp @@ -153,6 +153,84 @@ static TypeDeclarationStmt makeIterSpecDecl(std::list<ObjectName> &&names) { makeEntityList(std::move(names))); } +TYPE_PARSER(sourced(construct<OmpDirectiveSpecification>( + OmpDirectiveNameParser{}, maybe(indirect(Parser<OmpClauseList>{}))))) + +// --- Parsers for context traits ------------------------------------- + +TYPE_PARSER(construct<OmpTraitPropertyName>( // + (space >> charLiteralConstantWithoutKind) || + applyMem(&Name::ToString, Parser<Name>{}))) + +TYPE_PARSER(construct<OmpTraitScore>( // + "SCORE" >> parenthesized(scalarIntExpr))) + +TYPE_PARSER(construct<OmpTraitPropertyExtension::ExtensionValue>( + // Parse nested extension first. + construct<OmpTraitPropertyExtension::ExtensionValue>( + indirect(Parser<OmpTraitPropertyExtension>{})) || + construct<OmpTraitPropertyExtension::ExtensionValue>( + Parser<OmpTraitPropertyName>{}) || + construct<OmpTraitPropertyExtension::ExtensionValue>(scalarExpr))) + +TYPE_PARSER(construct<OmpTraitPropertyExtension>( // + Parser<OmpTraitPropertyName>{}, + parenthesized(nonemptySeparated( + Parser<OmpTraitPropertyExtension::ExtensionValue>{}, ","_tok)))) + +TYPE_PARSER(construct<OmpTraitProperty>( + // Try extension first, before OmpTraitPropertyName. + construct<OmpTraitProperty>(Parser<OmpTraitPropertyExtension>{}) || + construct<OmpTraitProperty>(Parser<OmpTraitPropertyName>{}) || + construct<OmpTraitProperty>(indirect(Parser<OmpClause>{})) || + construct<OmpTraitProperty>(scalarExpr))) + +TYPE_PARSER(construct<OmpTraitSelectorName::Value>( + "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<OmpTraitSelectorName>( + // Parse predefined names first (because of SIMD). + construct<OmpTraitSelectorName>(Parser<OmpTraitSelectorName::Value>{}) || + construct<OmpTraitSelectorName>(OmpDirectiveNameParser{}))) + +TYPE_PARSER(construct<OmpTraitSelector::Properties>( + maybe(Parser<OmpTraitScore>{} / ":"_tok), + nonemptySeparated(Parser<OmpTraitProperty>{}, ","_tok))) + +TYPE_PARSER(construct<OmpTraitSelector>( // + Parser<OmpTraitSelectorName>{}, // + maybe(parenthesized(Parser<OmpTraitSelector::Properties>{})))) + +TYPE_PARSER(construct<OmpTraitSetSelectorName::Value>( + "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<OmpTraitSetSelectorName>( + Parser<OmpTraitSetSelectorName::Value>{})) + +TYPE_PARSER(construct<OmpTraitSetSelector>( // + Parser<OmpTraitSetSelectorName>{}, + "=" >> braced(nonemptySeparated(Parser<OmpTraitSelector>{}, ","_tok)))) + +TYPE_PARSER(construct<OmpContextSelectorSpecification>( + nonemptySeparated(Parser<OmpTraitSetSelector>{}, ","_tok))) + +// Parser<OmpContextSelector> == Parser<traits::OmpContextSelectorSpecification> + // --- Parsers for clause modifiers ----------------------------------- TYPE_PARSER(construct<OmpAlignment>(scalarIntExpr)) diff --git a/flang/lib/Parser/token-parsers.h b/flang/lib/Parser/token-parsers.h index fe6bc1f69f576b..3e0c59b89d9649 100644 --- a/flang/lib/Parser/token-parsers.h +++ b/flang/lib/Parser/token-parsers.h @@ -215,6 +215,10 @@ template <class PA> inline constexpr auto bracketed(const PA &p) { return "[" >> p / "]"; } +template <class PA> inline constexpr auto braced(const PA &p) { + return "{" >> p / "}"; +} + // Quoted character literal constants. struct CharLiteralChar { using resultType = std::pair<char, bool /* was escaped */>; diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp index 58820476c51bc1..31a2c3bbc408d5 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<llvm::omp::Directive>(x.t)); + Walk(std::get<std::optional<common::Indirection<OmpClauseList>>>(x.t)); + } + void Unparse(const OmpTraitScore &x) { + Word("SCORE("); + Walk(x.v); + Put(")"); + } + void Unparse(const OmpTraitPropertyExtension &x) { + Walk(std::get<OmpTraitPropertyName>(x.t)); + Put("("); + Walk(std::get<OmpTraitPropertyExtension::ExtensionList>(x.t), ","); + Put(")"); + } + void Unparse(const OmpTraitSelector &x) { + Walk(std::get<OmpTraitSelectorName>(x.t)); + Walk(std::get<std::optional<OmpTraitSelector::Properties>>(x.t)); + } + void Unparse(const OmpTraitSelector::Properties &x) { + Put("("); + Walk(std::get<std::optional<OmpTraitScore>>(x.t), ": "); + Walk(std::get<std::list<OmpTraitProperty>>(x.t)); + Put(")"); + } + void Unparse(const OmpTraitSetSelector &x) { + Walk(std::get<OmpTraitSetSelectorName>(x.t)); + Put("={"); + Walk(std::get<std::list<OmpTraitSelector>>(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 6db43cf6f04bd3..67f7f65b7e422b 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<llvm::omp::Directive>(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 dc360957c873b7..1fc7e6c1e9baaa 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 39478b58a9070d..4e423ea1b43251 100644 --- a/flang/lib/Semantics/resolve-directives.cpp +++ b/flang/lib/Semantics/resolve-directives.cpp @@ -351,6 +351,12 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> { return true; } + bool Pre(const parser::OmpDirectiveSpecification &x) { + PushContext(x.source, std::get<llvm::omp::Directive>(x.t)); + return true; + } + void Post(const parser::OmpDirectiveSpecification &) { PopContext(); } + bool Pre(const parser::OpenMPBlockConstruct &); void Post(const parser::OpenMPBlockConstruct &); _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits