mirror of
https://github.com/intel/llvm.git
synced 2026-01-15 12:25:46 +08:00
[flang][OpenMP] Introduce variant argument, customize OmpArgument par… (#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.
This commit is contained in:
committed by
GitHub
parent
b7e20c7414
commit
d73ffe57f9
@@ -522,6 +522,7 @@ public:
|
||||
NODE(parser, OmpAtomicDefaultMemOrderClause)
|
||||
NODE(parser, OmpAutomapModifier)
|
||||
NODE_ENUM(OmpAutomapModifier, Value)
|
||||
NODE(parser, OmpBaseVariantNames)
|
||||
NODE(parser, OmpBeginDirective)
|
||||
NODE(parser, OmpBeginLoopDirective)
|
||||
NODE(parser, OmpBeginSectionsDirective)
|
||||
|
||||
@@ -3555,6 +3555,18 @@ struct OmpLocator {
|
||||
|
||||
WRAPPER_CLASS(OmpLocatorList, std::list<OmpLocator>);
|
||||
|
||||
// Ref: [4.5:58-60], [5.0:58-60], [5.1:63-68], [5.2:197-198], [6.0:334-336]
|
||||
//
|
||||
// Argument to DECLARE VARIANT with the base-name present. (When only
|
||||
// variant-name is present, it is a simple OmpObject).
|
||||
//
|
||||
// base-name-variant-name -> // since 4.5
|
||||
// base-name : variant-name
|
||||
struct OmpBaseVariantNames {
|
||||
TUPLE_CLASS_BOILERPLATE(OmpBaseVariantNames);
|
||||
std::tuple<OmpObject, OmpObject> t;
|
||||
};
|
||||
|
||||
// Ref: [5.0:326:10-16], [5.1:359:5-11], [5.2:163:2-7], [6.0:293:16-21]
|
||||
//
|
||||
// mapper-specifier ->
|
||||
@@ -3584,6 +3596,7 @@ struct OmpArgument {
|
||||
CharBlock source;
|
||||
UNION_CLASS_BOILERPLATE(OmpArgument);
|
||||
std::variant<OmpLocator, // {variable, extended, locator}-list-item
|
||||
OmpBaseVariantNames, // base-name:variant-name
|
||||
OmpMapperSpecifier, OmpReductionSpecifier>
|
||||
u;
|
||||
};
|
||||
|
||||
@@ -315,15 +315,56 @@ TYPE_PARSER( //
|
||||
construct<OmpLocator>(Parser<OmpObject>{}) ||
|
||||
construct<OmpLocator>(Parser<FunctionReference>{}))
|
||||
|
||||
TYPE_PARSER(sourced( //
|
||||
construct<OmpArgument>(Parser<OmpMapperSpecifier>{}) ||
|
||||
construct<OmpArgument>(Parser<OmpReductionSpecifier>{}) ||
|
||||
construct<OmpArgument>(Parser<OmpLocator>{})))
|
||||
TYPE_PARSER(construct<OmpBaseVariantNames>(
|
||||
Parser<OmpObject>{} / ":", Parser<OmpObject>{}))
|
||||
|
||||
// Make the parsing of OmpArgument directive-sensitive. The issue is that
|
||||
// name1:name2 can match either OmpBaseVariantNames or OmpReductionSpecifier.
|
||||
// In the former case, "name2" is a name of a function, in the latter, of a
|
||||
// type. To resolve the conflict we need information provided by name
|
||||
// resolution, but by that time we can't modify the AST anymore, and the
|
||||
// name resolution may have implicitly declared a symbol, or issued a message.
|
||||
template <llvm::omp::Directive Id = llvm::omp::Directive::OMPD_unknown>
|
||||
struct OmpArgumentParser {
|
||||
using resultType = OmpArgument;
|
||||
|
||||
std::optional<resultType> Parse(ParseState &state) const {
|
||||
constexpr auto parser{sourced(first( //
|
||||
construct<OmpArgument>(Parser<OmpMapperSpecifier>{}),
|
||||
// By default, prefer OmpReductionSpecifier over OmpBaseVariantNames.
|
||||
construct<OmpArgument>(Parser<OmpReductionSpecifier>{}),
|
||||
construct<OmpArgument>(Parser<OmpLocator>{})))};
|
||||
return parser.Parse(state);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct OmpArgumentParser<llvm::omp::Directive::OMPD_declare_variant> {
|
||||
using resultType = OmpArgument;
|
||||
|
||||
std::optional<resultType> Parse(ParseState &state) const {
|
||||
constexpr auto parser{sourced(first( //
|
||||
construct<OmpArgument>(Parser<OmpMapperSpecifier>{}),
|
||||
// In DECLARE_VARIANT parse OmpBaseVariantNames instead of
|
||||
// OmpReductionSpecifier.
|
||||
construct<OmpArgument>(Parser<OmpBaseVariantNames>{}),
|
||||
construct<OmpArgument>(Parser<OmpLocator>{})))};
|
||||
return parser.Parse(state);
|
||||
}
|
||||
};
|
||||
|
||||
TYPE_PARSER(construct<OmpLocatorList>(nonemptyList(Parser<OmpLocator>{})))
|
||||
|
||||
TYPE_PARSER(sourced( //
|
||||
construct<OmpArgumentList>(nonemptyList(Parser<OmpArgument>{}))))
|
||||
template <llvm::omp::Directive Id = llvm::omp::Directive::OMPD_unknown>
|
||||
struct OmpArgumentListParser {
|
||||
using resultType = OmpArgumentList;
|
||||
|
||||
std::optional<resultType> Parse(ParseState &state) const {
|
||||
return sourced(
|
||||
construct<OmpArgumentList>(nonemptyList(OmpArgumentParser<Id>{})))
|
||||
.Parse(state);
|
||||
}
|
||||
};
|
||||
|
||||
TYPE_PARSER( //
|
||||
construct<OmpTypeSpecifier>(Parser<DeclarationTypeSpec>{}) ||
|
||||
@@ -1312,12 +1353,23 @@ TYPE_PARSER(
|
||||
applyFunction<OmpDirectiveSpecification>(makeFlushFromOldSyntax,
|
||||
verbatim("FLUSH"_tok) / !lookAhead("("_tok),
|
||||
maybe(Parser<OmpClauseList>{}),
|
||||
maybe(parenthesized(Parser<OmpArgumentList>{})),
|
||||
maybe(parenthesized(
|
||||
OmpArgumentListParser<llvm::omp::Directive::OMPD_flush>{})),
|
||||
pure(OmpDirectiveSpecification::Flags::DeprecatedSyntax)))) ||
|
||||
// Parse DECLARE_VARIANT individually, because the "[base:]variant"
|
||||
// argument will conflict with DECLARE_REDUCTION's "ident:types...".
|
||||
predicated(Parser<OmpDirectiveName>{},
|
||||
IsDirective(llvm::omp::Directive::OMPD_declare_variant)) >=
|
||||
sourced(construct<OmpDirectiveSpecification>(
|
||||
sourced(OmpDirectiveNameParser{}),
|
||||
maybe(parenthesized(OmpArgumentListParser<
|
||||
llvm::omp::Directive::OMPD_declare_variant>{})),
|
||||
maybe(Parser<OmpClauseList>{}),
|
||||
pure(OmpDirectiveSpecification::Flags::None))) ||
|
||||
// Parse the standard syntax: directive [(arguments)] [clauses]
|
||||
sourced(construct<OmpDirectiveSpecification>( //
|
||||
sourced(OmpDirectiveNameParser{}),
|
||||
maybe(parenthesized(Parser<OmpArgumentList>{})),
|
||||
maybe(parenthesized(OmpArgumentListParser<>{})),
|
||||
maybe(Parser<OmpClauseList>{}),
|
||||
pure(OmpDirectiveSpecification::Flags::None))))
|
||||
|
||||
|
||||
@@ -2089,6 +2089,11 @@ public:
|
||||
// OpenMP Clauses & Directives
|
||||
void Unparse(const OmpArgumentList &x) { Walk(x.v, ", "); }
|
||||
|
||||
void Unparse(const OmpBaseVariantNames &x) {
|
||||
Walk(std::get<0>(x.t)); // OmpObject
|
||||
Put(":");
|
||||
Walk(std::get<1>(x.t)); // OmpObject
|
||||
}
|
||||
void Unparse(const OmpTypeNameList &x) { //
|
||||
Walk(x.v, ",");
|
||||
}
|
||||
|
||||
@@ -1998,6 +1998,10 @@ bool OmpVisitor::Pre(const parser::OmpDirectiveSpecification &x) {
|
||||
ProcessReductionSpecifier(spec, clauses);
|
||||
visitClauses = false;
|
||||
},
|
||||
[&](const parser::OmpBaseVariantNames &names) {
|
||||
Walk(std::get<0>(names.t));
|
||||
Walk(std::get<1>(names.t));
|
||||
},
|
||||
[&](const parser::OmpLocator &locator) {
|
||||
// Manually resolve names in CRITICAL directives. This is because
|
||||
// these names do not denote Fortran objects, and the CRITICAL
|
||||
|
||||
Reference in New Issue
Block a user