Skip to content

Commit d73ffe5

Browse files
authored
[flang][OpenMP] Introduce variant argument, customize OmpArgument par… (llvm#160372)
…sing The DECLARE_VARIANT directive takes two names separated by a colon as an argument: base-name:variant-name. Define OmpBaseVariantNames to represent this, since no existing argument alternative matches it. However, there is an issue. The syntax "name1:name2" can be the argument to DECLARE_VARIANT (if both names are OmpObjects), but it can also be a reduction-specifier if "name2" is a type. This conflict can only be resolved once we know what the names are, which is after name resolution has visited them. The problem is that name resolution has side-effects that may be (practically) impossible to undo (e.g. creating new symbols, emitting diagnostic messages). To avoid this problem this PR makes the parsing of OmpArgument directive- sensitive: when the directive is DECLARE_VARIANT, don't attempt to parse a reduction-specifier, consider OmpBaseVariantNames instead. Otherwise ignore OmpBaseVariantNames in favor of reduction-specifier.
1 parent b7e20c7 commit d73ffe5

File tree

5 files changed

+83
-8
lines changed

5 files changed

+83
-8
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -522,6 +522,7 @@ class ParseTreeDumper {
522522
NODE(parser, OmpAtomicDefaultMemOrderClause)
523523
NODE(parser, OmpAutomapModifier)
524524
NODE_ENUM(OmpAutomapModifier, Value)
525+
NODE(parser, OmpBaseVariantNames)
525526
NODE(parser, OmpBeginDirective)
526527
NODE(parser, OmpBeginLoopDirective)
527528
NODE(parser, OmpBeginSectionsDirective)

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3555,6 +3555,18 @@ struct OmpLocator {
35553555

35563556
WRAPPER_CLASS(OmpLocatorList, std::list<OmpLocator>);
35573557

3558+
// Ref: [4.5:58-60], [5.0:58-60], [5.1:63-68], [5.2:197-198], [6.0:334-336]
3559+
//
3560+
// Argument to DECLARE VARIANT with the base-name present. (When only
3561+
// variant-name is present, it is a simple OmpObject).
3562+
//
3563+
// base-name-variant-name -> // since 4.5
3564+
// base-name : variant-name
3565+
struct OmpBaseVariantNames {
3566+
TUPLE_CLASS_BOILERPLATE(OmpBaseVariantNames);
3567+
std::tuple<OmpObject, OmpObject> t;
3568+
};
3569+
35583570
// Ref: [5.0:326:10-16], [5.1:359:5-11], [5.2:163:2-7], [6.0:293:16-21]
35593571
//
35603572
// mapper-specifier ->
@@ -3584,6 +3596,7 @@ struct OmpArgument {
35843596
CharBlock source;
35853597
UNION_CLASS_BOILERPLATE(OmpArgument);
35863598
std::variant<OmpLocator, // {variable, extended, locator}-list-item
3599+
OmpBaseVariantNames, // base-name:variant-name
35873600
OmpMapperSpecifier, OmpReductionSpecifier>
35883601
u;
35893602
};

flang/lib/Parser/openmp-parsers.cpp

Lines changed: 60 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -315,15 +315,56 @@ TYPE_PARSER( //
315315
construct<OmpLocator>(Parser<OmpObject>{}) ||
316316
construct<OmpLocator>(Parser<FunctionReference>{}))
317317

318-
TYPE_PARSER(sourced( //
319-
construct<OmpArgument>(Parser<OmpMapperSpecifier>{}) ||
320-
construct<OmpArgument>(Parser<OmpReductionSpecifier>{}) ||
321-
construct<OmpArgument>(Parser<OmpLocator>{})))
318+
TYPE_PARSER(construct<OmpBaseVariantNames>(
319+
Parser<OmpObject>{} / ":", Parser<OmpObject>{}))
320+
321+
// Make the parsing of OmpArgument directive-sensitive. The issue is that
322+
// name1:name2 can match either OmpBaseVariantNames or OmpReductionSpecifier.
323+
// In the former case, "name2" is a name of a function, in the latter, of a
324+
// type. To resolve the conflict we need information provided by name
325+
// resolution, but by that time we can't modify the AST anymore, and the
326+
// name resolution may have implicitly declared a symbol, or issued a message.
327+
template <llvm::omp::Directive Id = llvm::omp::Directive::OMPD_unknown>
328+
struct OmpArgumentParser {
329+
using resultType = OmpArgument;
330+
331+
std::optional<resultType> Parse(ParseState &state) const {
332+
constexpr auto parser{sourced(first( //
333+
construct<OmpArgument>(Parser<OmpMapperSpecifier>{}),
334+
// By default, prefer OmpReductionSpecifier over OmpBaseVariantNames.
335+
construct<OmpArgument>(Parser<OmpReductionSpecifier>{}),
336+
construct<OmpArgument>(Parser<OmpLocator>{})))};
337+
return parser.Parse(state);
338+
}
339+
};
340+
341+
template <>
342+
struct OmpArgumentParser<llvm::omp::Directive::OMPD_declare_variant> {
343+
using resultType = OmpArgument;
344+
345+
std::optional<resultType> Parse(ParseState &state) const {
346+
constexpr auto parser{sourced(first( //
347+
construct<OmpArgument>(Parser<OmpMapperSpecifier>{}),
348+
// In DECLARE_VARIANT parse OmpBaseVariantNames instead of
349+
// OmpReductionSpecifier.
350+
construct<OmpArgument>(Parser<OmpBaseVariantNames>{}),
351+
construct<OmpArgument>(Parser<OmpLocator>{})))};
352+
return parser.Parse(state);
353+
}
354+
};
322355

323356
TYPE_PARSER(construct<OmpLocatorList>(nonemptyList(Parser<OmpLocator>{})))
324357

325-
TYPE_PARSER(sourced( //
326-
construct<OmpArgumentList>(nonemptyList(Parser<OmpArgument>{}))))
358+
template <llvm::omp::Directive Id = llvm::omp::Directive::OMPD_unknown>
359+
struct OmpArgumentListParser {
360+
using resultType = OmpArgumentList;
361+
362+
std::optional<resultType> Parse(ParseState &state) const {
363+
return sourced(
364+
construct<OmpArgumentList>(nonemptyList(OmpArgumentParser<Id>{})))
365+
.Parse(state);
366+
}
367+
};
327368

328369
TYPE_PARSER( //
329370
construct<OmpTypeSpecifier>(Parser<DeclarationTypeSpec>{}) ||
@@ -1312,12 +1353,23 @@ TYPE_PARSER(
13121353
applyFunction<OmpDirectiveSpecification>(makeFlushFromOldSyntax,
13131354
verbatim("FLUSH"_tok) / !lookAhead("("_tok),
13141355
maybe(Parser<OmpClauseList>{}),
1315-
maybe(parenthesized(Parser<OmpArgumentList>{})),
1356+
maybe(parenthesized(
1357+
OmpArgumentListParser<llvm::omp::Directive::OMPD_flush>{})),
13161358
pure(OmpDirectiveSpecification::Flags::DeprecatedSyntax)))) ||
1359+
// Parse DECLARE_VARIANT individually, because the "[base:]variant"
1360+
// argument will conflict with DECLARE_REDUCTION's "ident:types...".
1361+
predicated(Parser<OmpDirectiveName>{},
1362+
IsDirective(llvm::omp::Directive::OMPD_declare_variant)) >=
1363+
sourced(construct<OmpDirectiveSpecification>(
1364+
sourced(OmpDirectiveNameParser{}),
1365+
maybe(parenthesized(OmpArgumentListParser<
1366+
llvm::omp::Directive::OMPD_declare_variant>{})),
1367+
maybe(Parser<OmpClauseList>{}),
1368+
pure(OmpDirectiveSpecification::Flags::None))) ||
13171369
// Parse the standard syntax: directive [(arguments)] [clauses]
13181370
sourced(construct<OmpDirectiveSpecification>( //
13191371
sourced(OmpDirectiveNameParser{}),
1320-
maybe(parenthesized(Parser<OmpArgumentList>{})),
1372+
maybe(parenthesized(OmpArgumentListParser<>{})),
13211373
maybe(Parser<OmpClauseList>{}),
13221374
pure(OmpDirectiveSpecification::Flags::None))))
13231375

flang/lib/Parser/unparse.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2089,6 +2089,11 @@ class UnparseVisitor {
20892089
// OpenMP Clauses & Directives
20902090
void Unparse(const OmpArgumentList &x) { Walk(x.v, ", "); }
20912091

2092+
void Unparse(const OmpBaseVariantNames &x) {
2093+
Walk(std::get<0>(x.t)); // OmpObject
2094+
Put(":");
2095+
Walk(std::get<1>(x.t)); // OmpObject
2096+
}
20922097
void Unparse(const OmpTypeNameList &x) { //
20932098
Walk(x.v, ",");
20942099
}

flang/lib/Semantics/resolve-names.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1998,6 +1998,10 @@ bool OmpVisitor::Pre(const parser::OmpDirectiveSpecification &x) {
19981998
ProcessReductionSpecifier(spec, clauses);
19991999
visitClauses = false;
20002000
},
2001+
[&](const parser::OmpBaseVariantNames &names) {
2002+
Walk(std::get<0>(names.t));
2003+
Walk(std::get<1>(names.t));
2004+
},
20012005
[&](const parser::OmpLocator &locator) {
20022006
// Manually resolve names in CRITICAL directives. This is because
20032007
// these names do not denote Fortran objects, and the CRITICAL

0 commit comments

Comments
 (0)