-
Notifications
You must be signed in to change notification settings - Fork 12.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[flang][OpenMP] Parsing context selectors for METADIRECTIVE #121815
base: users/kparzysz/spr/m01-applymem
Are you sure you want to change the base?
[flang][OpenMP] Parsing context selectors for METADIRECTIVE #121815
Conversation
This is just adding parsers for context selectors. There are no tests because there is no way to execute these parsers yet.
@llvm/pr-subscribers-flang-semantics @llvm/pr-subscribers-flang-parser Author: Krzysztof Parzyszek (kparzysz) ChangesThis is just adding parsers for context selectors. There are no tests because there is no way to execute these parsers yet. Full diff: https://github.com/llvm/llvm-project/pull/121815.diff 9 Files Affected:
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/pr-subscribers-flang-openmp Author: Krzysztof Parzyszek (kparzysz) ChangesThis is just adding parsers for context selectors. There are no tests because there is no way to execute these parsers yet. Full diff: https://github.com/llvm/llvm-project/pull/121815.diff 9 Files Affected:
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 &);
|
The next PR: #121817 |
This is just adding parsers for context selectors. There are no tests because there is no way to execute these parsers yet.