Skip to content

Commit 3bfe74e

Browse files
committed
[flang][OpenMP] Make parsing of trait properties more context-sensitive
A trait poperty can be one of serveral alternatives, and each property in a list was parsed as if it could be any of these alternatives independently from other properties. This made the parsing vulnerable to certain ambiguities in the trait grammar (provided in the OpenMP spec). At the same time the OpenMP spec gives the expected types of properties for almost every trait: all properties listed for a given trait are usually of the same type, e.g. names, clauses, etc. Incorporate these restrictions into the parser, and additionally use property extensions as the fallback if the parsing of the expected property type failed. This is intended to allow the parser to succeed, and instead let the semantic-checking code emit a more user-friendly message.
1 parent 0fe8469 commit 3bfe74e

File tree

4 files changed

+116
-56
lines changed

4 files changed

+116
-56
lines changed

flang/include/flang/Parser/dump-parse-tree.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,7 @@ class ParseTreeDumper {
479479
NODE(parser, OmpTraitPropertyName)
480480
NODE(parser, OmpTraitScore)
481481
NODE(parser, OmpTraitPropertyExtension)
482-
NODE(OmpTraitPropertyExtension, ExtensionValue)
482+
NODE(OmpTraitPropertyExtension, Complex)
483483
NODE(parser, OmpTraitProperty)
484484
NODE(parser, OmpTraitSelectorName)
485485
NODE_ENUM(OmpTraitSelectorName, Value)

flang/include/flang/Parser/parse-tree.h

Lines changed: 13 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3505,37 +3505,22 @@ struct OmpTraitScore {
35053505
};
35063506

35073507
// trait-property-extension ->
3508-
// trait-property-name (trait-property-value, ...)
3509-
// trait-property-value ->
35103508
// trait-property-name |
3511-
// scalar-integer-expression |
3512-
// trait-property-extension
3513-
//
3514-
// The grammar in OpenMP 5.2+ spec is ambiguous, the above is a different
3515-
// version (but equivalent) that doesn't have ambiguities.
3516-
// The ambiguity is in
3517-
// trait-property:
3518-
// trait-property-name <- (a)
3519-
// trait-property-clause
3520-
// trait-property-expression <- (b)
3521-
// trait-property-extension <- this conflicts with (a) and (b)
3522-
// trait-property-extension:
3523-
// trait-property-name <- conflict with (a)
3524-
// identifier(trait-property-extension[, trait-property-extension[, ...]])
3525-
// constant integer expression <- conflict with (b)
3509+
// scalar-expr |
3510+
// trait-property-name (trait-property-extension, ...)
35263511
//
35273512
struct OmpTraitPropertyExtension {
35283513
CharBlock source;
3529-
TUPLE_CLASS_BOILERPLATE(OmpTraitPropertyExtension);
3530-
struct ExtensionValue {
3514+
UNION_CLASS_BOILERPLATE(OmpTraitPropertyExtension);
3515+
struct Complex { // name (prop-ext, prop-ext, ...)
35313516
CharBlock source;
3532-
UNION_CLASS_BOILERPLATE(ExtensionValue);
3533-
std::variant<OmpTraitPropertyName, ScalarExpr,
3534-
common::Indirection<OmpTraitPropertyExtension>>
3535-
u;
3517+
TUPLE_CLASS_BOILERPLATE(Complex);
3518+
std::tuple<OmpTraitPropertyName,
3519+
std::list<common::Indirection<OmpTraitPropertyExtension>>>
3520+
t;
35363521
};
3537-
using ExtensionList = std::list<ExtensionValue>;
3538-
std::tuple<OmpTraitPropertyName, ExtensionList> t;
3522+
3523+
std::variant<OmpTraitPropertyName, ScalarExpr, Complex> u;
35393524
};
35403525

35413526
// trait-property ->
@@ -3568,9 +3553,10 @@ struct OmpTraitProperty {
35683553
// UID | T // unique-string-id /impl-defined
35693554
// VENDOR | I // name-list (vendor-id /add-def-doc)
35703555
// EXTENSION | I // name-list (ext_name /impl-defined)
3571-
// ATOMIC_DEFAULT_MEM_ORDER I | // value of admo
3556+
// ATOMIC_DEFAULT_MEM_ORDER I | // clause-list (value of admo)
35723557
// REQUIRES | I // clause-list (from requires)
35733558
// CONDITION U // logical-expr
3559+
// <other name> I // treated as extension
35743560
//
35753561
// Trait-set-selectors:
35763562
// [D]evice, [T]arget_device, [C]onstruct, [I]mplementation, [U]ser.
@@ -3579,7 +3565,7 @@ struct OmpTraitSelectorName {
35793565
UNION_CLASS_BOILERPLATE(OmpTraitSelectorName);
35803566
ENUM_CLASS(Value, Arch, Atomic_Default_Mem_Order, Condition, Device_Num,
35813567
Extension, Isa, Kind, Requires, Simd, Uid, Vendor)
3582-
std::variant<Value, llvm::omp::Directive> u;
3568+
std::variant<Value, llvm::omp::Directive, std::string> u;
35833569
};
35843570

35853571
// trait-selector ->

flang/lib/Parser/openmp-parsers.cpp

Lines changed: 99 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -158,31 +158,23 @@ static TypeDeclarationStmt makeIterSpecDecl(std::list<ObjectName> &&names) {
158158
static std::string nameToString(Name &&name) { return name.ToString(); }
159159

160160
TYPE_PARSER(sourced(construct<OmpTraitPropertyName>( //
161-
(space >> charLiteralConstantWithoutKind) ||
162-
applyFunction(nameToString, Parser<Name>{}))))
161+
construct<OmpTraitPropertyName>(space >> charLiteralConstantWithoutKind) ||
162+
construct<OmpTraitPropertyName>(
163+
applyFunction(nameToString, Parser<Name>{})))))
163164

164165
TYPE_PARSER(sourced(construct<OmpTraitScore>( //
165-
"SCORE" >> parenthesized(scalarIntExpr))))
166+
"SCORE"_tok >> parenthesized(scalarIntExpr))))
166167

167-
TYPE_PARSER(sourced(construct<OmpTraitPropertyExtension::ExtensionValue>(
168-
// Parse nested extension first.
169-
construct<OmpTraitPropertyExtension::ExtensionValue>(
170-
indirect(Parser<OmpTraitPropertyExtension>{})) ||
171-
construct<OmpTraitPropertyExtension::ExtensionValue>(
172-
Parser<OmpTraitPropertyName>{}) ||
173-
construct<OmpTraitPropertyExtension::ExtensionValue>(scalarExpr))))
174-
175-
TYPE_PARSER(sourced(construct<OmpTraitPropertyExtension>( //
168+
TYPE_PARSER(sourced(construct<OmpTraitPropertyExtension::Complex>(
176169
Parser<OmpTraitPropertyName>{},
177170
parenthesized(nonemptySeparated(
178-
Parser<OmpTraitPropertyExtension::ExtensionValue>{}, ","_tok)))))
171+
indirect(Parser<OmpTraitPropertyExtension>{}), ","_tok)))))
179172

180-
TYPE_PARSER(sourced(construct<OmpTraitProperty>(
181-
// Try clause first, then extension before OmpTraitPropertyName.
182-
construct<OmpTraitProperty>(indirect(Parser<OmpClause>{})) ||
183-
construct<OmpTraitProperty>(Parser<OmpTraitPropertyExtension>{}) ||
184-
construct<OmpTraitProperty>(Parser<OmpTraitPropertyName>{}) ||
185-
construct<OmpTraitProperty>(scalarExpr))))
173+
TYPE_PARSER(sourced(construct<OmpTraitPropertyExtension>(
174+
construct<OmpTraitPropertyExtension>(
175+
Parser<OmpTraitPropertyExtension::Complex>{}) ||
176+
construct<OmpTraitPropertyExtension>(Parser<OmpTraitPropertyName>{}) ||
177+
construct<OmpTraitPropertyExtension>(scalarExpr))))
186178

187179
TYPE_PARSER(construct<OmpTraitSelectorName::Value>(
188180
"ARCH" >> pure(OmpTraitSelectorName::Value::Arch) ||
@@ -201,15 +193,96 @@ TYPE_PARSER(construct<OmpTraitSelectorName::Value>(
201193
TYPE_PARSER(sourced(construct<OmpTraitSelectorName>(
202194
// Parse predefined names first (because of SIMD).
203195
construct<OmpTraitSelectorName>(Parser<OmpTraitSelectorName::Value>{}) ||
204-
construct<OmpTraitSelectorName>(OmpDirectiveNameParser{}))))
196+
construct<OmpTraitSelectorName>(OmpDirectiveNameParser{}) ||
197+
// identifier-or-string for extensions
198+
construct<OmpTraitSelectorName>(
199+
applyFunction(nameToString, Parser<Name>{})) ||
200+
construct<OmpTraitSelectorName>(space >> charLiteralConstantWithoutKind))))
201+
202+
// Parser for OmpTraitSelector::Properties
203+
template <typename... PropParser>
204+
static constexpr auto propertyListParser(PropParser... pp) {
205+
// Parse the property list "(score(expr): item1...)" in three steps:
206+
// 1. Parse the "("
207+
// 2. Parse the optional "score(expr):"
208+
// 3. Parse the "item1, ...)", together with the ")".
209+
// The reason for including the ")" in the 3rd step is to force parsing
210+
// the entire list in each of the alternative property parsers. Otherwise,
211+
// the name parser could stop after "foo" in "(foo, bar(1))", without
212+
// allowing the next parser to give the list a try.
213+
214+
using P = OmpTraitProperty;
215+
return maybe("(" >>
216+
construct<OmpTraitSelector::Properties>(
217+
maybe(Parser<OmpTraitScore>{} / ":"_tok),
218+
(attempt(nonemptySeparated(construct<P>(pp), ","_tok) / ")"_tok) ||
219+
...)));
220+
}
221+
222+
// Parser for OmpTraitSelector
223+
struct TraitSelectorParser {
224+
using resultType = OmpTraitSelector;
225+
226+
constexpr TraitSelectorParser(Parser<OmpTraitSelectorName> p) : np(p) {}
227+
228+
std::optional<resultType> Parse(ParseState &state) const {
229+
auto name{attempt(np).Parse(state)};
230+
if (!name.has_value()) {
231+
return std::nullopt;
232+
}
233+
234+
// Default fallback parser for lists that cannot be parser using the
235+
// primary property parser.
236+
auto extParser{Parser<OmpTraitPropertyExtension>{}};
237+
238+
if (auto *v{std::get_if<OmpTraitSelectorName::Value>(&name->u)}) {
239+
switch (*v) {
240+
// name-list properties
241+
case OmpTraitSelectorName::Value::Arch: // [6.0:319:18]
242+
case OmpTraitSelectorName::Value::Extension: // [6.0:319:30]
243+
case OmpTraitSelectorName::Value::Isa: // [6.0:319:15]
244+
case OmpTraitSelectorName::Value::Kind: // [6.0:319:10]
245+
case OmpTraitSelectorName::Value::Uid: // [6.0:319:23](*)
246+
case OmpTraitSelectorName::Value::Vendor: { // [6.0:319:27]
247+
auto pp{propertyListParser(Parser<OmpTraitPropertyName>{}, extParser)};
248+
return OmpTraitSelector(std::move(*name), std::move(*pp.Parse(state)));
249+
}
250+
// clause-list
251+
case OmpTraitSelectorName::Value::Atomic_Default_Mem_Order:
252+
// [6.0:321:26-29](*)
253+
case OmpTraitSelectorName::Value::Requires: // [6.0:319:33]
254+
case OmpTraitSelectorName::Value::Simd: { // [6.0:318:31]
255+
auto pp{propertyListParser(indirect(Parser<OmpClause>{}), extParser)};
256+
return OmpTraitSelector(std::move(*name), std::move(*pp.Parse(state)));
257+
}
258+
// expr-list
259+
case OmpTraitSelectorName::Value::Condition: // [6.0:321:33](*)
260+
case OmpTraitSelectorName::Value::Device_Num: { // [6.0:321:23-24](*)
261+
auto pp{propertyListParser(scalarExpr, extParser)};
262+
return OmpTraitSelector(std::move(*name), std::move(*pp.Parse(state)));
263+
}
264+
// (*) The spec doesn't assign any list-type to these traits, but for
265+
// convenience they can be treated as if they were.
266+
} // switch
267+
} else {
268+
// The other alternatives are `llvm::omp::Directive`, and `std::string`.
269+
// The former doesn't take any properties[1], the latter is a name of an
270+
// extension[2].
271+
// [1] [6.0:319:1-2]
272+
// [2] [6.0:319:36-37]
273+
auto pp{propertyListParser(extParser)};
274+
return OmpTraitSelector(std::move(*name), std::move(*pp.Parse(state)));
275+
}
205276

206-
TYPE_PARSER(construct<OmpTraitSelector::Properties>(
207-
maybe(Parser<OmpTraitScore>{} / ":"_tok),
208-
nonemptySeparated(Parser<OmpTraitProperty>{}, ","_tok)))
277+
llvm_unreachable("Unhandled trait name?");
278+
}
279+
280+
private:
281+
const Parser<OmpTraitSelectorName> np;
282+
};
209283

210-
TYPE_PARSER(sourced(construct<OmpTraitSelector>( //
211-
Parser<OmpTraitSelectorName>{}, //
212-
maybe(parenthesized(Parser<OmpTraitSelector::Properties>{})))))
284+
TYPE_PARSER(construct<OmpTraitSelector>(
285+
TraitSelectorParser(Parser<OmpTraitSelectorName>{})))
213286

214287
TYPE_PARSER(construct<OmpTraitSetSelectorName::Value>(
215288
"CONSTRUCT" >> pure(OmpTraitSetSelectorName::Value::Construct) ||

flang/lib/Parser/unparse.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2075,10 +2075,11 @@ class UnparseVisitor {
20752075
Walk(x.v);
20762076
Put(")");
20772077
}
2078-
void Unparse(const OmpTraitPropertyExtension &x) {
2078+
void Unparse(const OmpTraitPropertyExtension::Complex &x) {
2079+
using PropList = std::list<common::Indirection<OmpTraitPropertyExtension>>;
20792080
Walk(std::get<OmpTraitPropertyName>(x.t));
20802081
Put("(");
2081-
Walk(std::get<OmpTraitPropertyExtension::ExtensionList>(x.t), ",");
2082+
Walk(std::get<PropList>(x.t), ",");
20822083
Put(")");
20832084
}
20842085
void Unparse(const OmpTraitSelector &x) {

0 commit comments

Comments
 (0)