Skip to content

Commit 70e96dc

Browse files
authored
[flang][OpenMP] Parsing context selectors for METADIRECTIVE (#121815)
This is just adding parsers for context selectors. There are no tests because there is no way to execute these parsers yet.
1 parent 372044e commit 70e96dc

File tree

8 files changed

+305
-32
lines changed

8 files changed

+305
-32
lines changed

flang/docs/ParserCombinators.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ collect the values that they return.
141141
* `applyLambda([](&&x){}, p1, p2, ...)` is the same thing, but for lambdas
142142
and other function objects.
143143
* `applyMem(mf, p1, p2, ...)` is the same thing, but invokes a member
144-
function of the result of the first parser for updates in place.
144+
function of the result of the first parser.
145145

146146
### Token Parsers
147147
Last, we have these basic parsers on which the actual grammar of the Fortran

flang/include/flang/Parser/characters.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@ inline constexpr bool IsValidFortranTokenCharacter(char ch) {
180180
case '>':
181181
case '[':
182182
case ']':
183+
case '{': // Used in OpenMP context selector specification
184+
case '}': //
183185
return true;
184186
default:
185187
return IsLegalIdentifierStart(ch) || IsDecimalDigit(ch);

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,19 @@ class ParseTreeDumper {
476476
NODE(parser, NullInit)
477477
NODE(parser, ObjectDecl)
478478
NODE(parser, OldParameterStmt)
479+
NODE(parser, OmpTraitPropertyName)
480+
NODE(parser, OmpTraitScore)
481+
NODE(parser, OmpTraitPropertyExtension)
482+
NODE(OmpTraitPropertyExtension, ExtensionValue)
483+
NODE(parser, OmpTraitProperty)
484+
NODE(parser, OmpTraitSelectorName)
485+
NODE_ENUM(OmpTraitSelectorName, Value)
486+
NODE(parser, OmpTraitSelector)
487+
NODE(OmpTraitSelector, Properties)
488+
NODE(parser, OmpTraitSetSelectorName)
489+
NODE_ENUM(OmpTraitSetSelectorName, Value)
490+
NODE(parser, OmpTraitSetSelector)
491+
NODE(parser, OmpContextSelectorSpecification)
479492
NODE(parser, OmpMapper)
480493
NODE(parser, OmpMapType)
481494
NODE_ENUM(OmpMapType, Value)

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

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3453,6 +3453,9 @@ WRAPPER_CLASS(PauseStmt, std::optional<StopCode>);
34533453

34543454
// --- Common definitions
34553455

3456+
struct OmpClause;
3457+
struct OmpClauseList;
3458+
34563459
// 2.1 Directives or clauses may accept a list or extended-list.
34573460
// A list item is a variable, array section or common block name (enclosed
34583461
// in slashes). An extended list item is a list item or a procedure Name.
@@ -3474,6 +3477,150 @@ WRAPPER_CLASS(OmpObjectList, std::list<OmpObject>);
34743477

34753478
#define MODIFIERS() std::optional<std::list<Modifier>>
34763479

3480+
inline namespace traits {
3481+
// trait-property-name ->
3482+
// identifier | string-literal
3483+
//
3484+
// This is a bit of a problematic case. The spec says that a word in quotes,
3485+
// and the same word without quotes are equivalent. We currently parse both
3486+
// as a string, but it's likely just a temporary solution.
3487+
//
3488+
// The problem is that trait-property can be (among other things) a
3489+
// trait-property-name or a trait-property-expression. A simple identifier
3490+
// can be either, there is no reasonably simple way of telling them apart
3491+
// in the parser. There is a similar issue with extensions. Some of that
3492+
// disambiguation may need to be done in the "canonicalization" pass and
3493+
// then some of those AST nodes would be rewritten into different ones.
3494+
//
3495+
struct OmpTraitPropertyName {
3496+
CharBlock source;
3497+
WRAPPER_CLASS_BOILERPLATE(OmpTraitPropertyName, std::string);
3498+
};
3499+
3500+
// trait-score ->
3501+
// SCORE(non-negative-const-integer-expression)
3502+
struct OmpTraitScore {
3503+
CharBlock source;
3504+
WRAPPER_CLASS_BOILERPLATE(OmpTraitScore, ScalarIntExpr);
3505+
};
3506+
3507+
// trait-property-extension ->
3508+
// trait-property-name (trait-property-value, ...)
3509+
// trait-property-value ->
3510+
// 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)
3526+
//
3527+
struct OmpTraitPropertyExtension {
3528+
CharBlock source;
3529+
TUPLE_CLASS_BOILERPLATE(OmpTraitPropertyExtension);
3530+
struct ExtensionValue {
3531+
CharBlock source;
3532+
UNION_CLASS_BOILERPLATE(ExtensionValue);
3533+
std::variant<OmpTraitPropertyName, ScalarExpr,
3534+
common::Indirection<OmpTraitPropertyExtension>>
3535+
u;
3536+
};
3537+
using ExtensionList = std::list<ExtensionValue>;
3538+
std::tuple<OmpTraitPropertyName, ExtensionList> t;
3539+
};
3540+
3541+
// trait-property ->
3542+
// trait-property-name | OmpClause |
3543+
// trait-property-expression | trait-property-extension
3544+
// trait-property-expression ->
3545+
// scalar-logical-expression | scalar-integer-expression
3546+
//
3547+
// The parser for a logical expression will accept an integer expression,
3548+
// and if it's not logical, it will flag an error later. The same thing
3549+
// will happen if the scalar integer expression sees a logical expresion.
3550+
// To avoid this, parse all expressions as scalar expressions.
3551+
struct OmpTraitProperty {
3552+
CharBlock source;
3553+
UNION_CLASS_BOILERPLATE(OmpTraitProperty);
3554+
std::variant<OmpTraitPropertyName, common::Indirection<OmpClause>,
3555+
ScalarExpr, // trait-property-expresion
3556+
OmpTraitPropertyExtension>
3557+
u;
3558+
};
3559+
3560+
// trait-selector-name ->
3561+
// KIND | DT // name-list (host, nohost, +/add-def-doc)
3562+
// ISA | DT // name-list (isa_name, ... /impl-defined)
3563+
// ARCH | DT // name-list (arch_name, ... /impl-defined)
3564+
// directive-name | C // no properties
3565+
// SIMD | C // clause-list (from declare_simd)
3566+
// // (at least simdlen, inbranch/notinbranch)
3567+
// DEVICE_NUM | T // device-number
3568+
// UID | T // unique-string-id /impl-defined
3569+
// VENDOR | I // name-list (vendor-id /add-def-doc)
3570+
// EXTENSION | I // name-list (ext_name /impl-defined)
3571+
// ATOMIC_DEFAULT_MEM_ORDER I | // value of admo
3572+
// REQUIRES | I // clause-list (from requires)
3573+
// CONDITION U // logical-expr
3574+
//
3575+
// Trait-set-selectors:
3576+
// [D]evice, [T]arget_device, [C]onstruct, [I]mplementation, [U]ser.
3577+
struct OmpTraitSelectorName {
3578+
CharBlock source;
3579+
UNION_CLASS_BOILERPLATE(OmpTraitSelectorName);
3580+
ENUM_CLASS(Value, Arch, Atomic_Default_Mem_Order, Condition, Device_Num,
3581+
Extension, Isa, Kind, Requires, Simd, Uid, Vendor)
3582+
std::variant<Value, llvm::omp::Directive> u;
3583+
};
3584+
3585+
// trait-selector ->
3586+
// trait-selector-name |
3587+
// trait-selector-name ([trait-score:] trait-property, ...)
3588+
struct OmpTraitSelector {
3589+
CharBlock source;
3590+
TUPLE_CLASS_BOILERPLATE(OmpTraitSelector);
3591+
struct Properties {
3592+
TUPLE_CLASS_BOILERPLATE(Properties);
3593+
std::tuple<std::optional<OmpTraitScore>, std::list<OmpTraitProperty>> t;
3594+
};
3595+
std::tuple<OmpTraitSelectorName, std::optional<Properties>> t;
3596+
};
3597+
3598+
// trait-set-selector-name ->
3599+
// CONSTRUCT | DEVICE | IMPLEMENTATION | USER | // since 5.0
3600+
// TARGET_DEVICE // since 5.1
3601+
struct OmpTraitSetSelectorName {
3602+
CharBlock source;
3603+
ENUM_CLASS(Value, Construct, Device, Implementation, Target_Device, User)
3604+
WRAPPER_CLASS_BOILERPLATE(OmpTraitSetSelectorName, Value);
3605+
};
3606+
3607+
// trait-set-selector ->
3608+
// trait-set-selector-name = {trait-selector, ...}
3609+
struct OmpTraitSetSelector {
3610+
CharBlock source;
3611+
TUPLE_CLASS_BOILERPLATE(OmpTraitSetSelector);
3612+
std::tuple<OmpTraitSetSelectorName, std::list<OmpTraitSelector>> t;
3613+
};
3614+
3615+
// context-selector-specification ->
3616+
// trait-set-selector, ...
3617+
struct OmpContextSelectorSpecification { // Modifier
3618+
CharBlock source;
3619+
WRAPPER_CLASS_BOILERPLATE(
3620+
OmpContextSelectorSpecification, std::list<OmpTraitSetSelector>);
3621+
};
3622+
} // namespace traits
3623+
34773624
inline namespace modifier {
34783625
// For uniformity, in all keyword modifiers the name of the type defined
34793626
// by ENUM_CLASS is "Value", e.g.
@@ -3744,6 +3891,9 @@ struct OmpVariableCategory {
37443891
ENUM_CLASS(Value, Aggregate, All, Allocatable, Pointer, Scalar)
37453892
WRAPPER_CLASS_BOILERPLATE(OmpVariableCategory, Value);
37463893
};
3894+
3895+
// context-selector
3896+
using OmpContextSelector = traits::OmpContextSelectorSpecification;
37473897
} // namespace modifier
37483898

37493899
// --- Clauses

flang/lib/Parser/basic-parsers.h

Lines changed: 23 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -580,11 +580,11 @@ template <typename PA> inline constexpr auto defaulted(PA p) {
580580
// applyLambda(f, ...) is the same concept extended to std::function<> functors.
581581
// It is not constexpr.
582582
//
583-
// Member function application is supported by applyMem(f, a). If the
584-
// parser a succeeds and returns some value ax, the result is that returned
585-
// by ax.f(). Additional parser arguments can be specified to supply their
586-
// results to the member function call, so applyMem(f, a, b) succeeds if
587-
// both a and b do so and returns the result of calling ax.f(std::move(bx)).
583+
// Member function application is supported by applyMem(&C::f, a). If the
584+
// parser a succeeds and returns some value ax of type C, the result is that
585+
// returned by ax.f(). Additional parser arguments can be specified to supply
586+
// their results to the member function call, so applyMem(&C::f, a, b) succeeds
587+
// if both a and b do so and returns the result of calling ax.f(std::move(bx)).
588588

589589
// Runs a sequence of parsers until one fails or all have succeeded.
590590
// Collects their results in a std::tuple<std::optional<>...>.
@@ -654,39 +654,31 @@ inline /* not constexpr */ auto applyLambda(
654654
}
655655

656656
// Member function application
657-
template <typename OBJPARSER, typename... PARSER> class AMFPHelper {
658-
using resultType = typename OBJPARSER::resultType;
659-
660-
public:
661-
using type = void (resultType::*)(typename PARSER::resultType &&...);
662-
};
663-
template <typename OBJPARSER, typename... PARSER>
664-
using ApplicableMemberFunctionPointer =
665-
typename AMFPHelper<OBJPARSER, PARSER...>::type;
666-
667-
template <typename OBJPARSER, typename... PARSER, std::size_t... J>
668-
inline auto ApplyHelperMember(
669-
ApplicableMemberFunctionPointer<OBJPARSER, PARSER...> mfp,
670-
ApplyArgs<OBJPARSER, PARSER...> &&args, std::index_sequence<J...>) ->
671-
typename OBJPARSER::resultType {
672-
((*std::get<0>(args)).*mfp)(std::move(*std::get<J + 1>(args))...);
673-
return std::get<0>(std::move(args));
657+
template <typename MEMFUNC, typename OBJPARSER, typename... PARSER,
658+
std::size_t... J>
659+
inline auto ApplyHelperMember(MEMFUNC mfp,
660+
ApplyArgs<OBJPARSER, PARSER...> &&args, std::index_sequence<J...>) {
661+
return ((*std::get<0>(args)).*mfp)(std::move(*std::get<J + 1>(args))...);
674662
}
675663

676-
template <typename OBJPARSER, typename... PARSER> class ApplyMemberFunction {
677-
using funcType = ApplicableMemberFunctionPointer<OBJPARSER, PARSER...>;
664+
template <typename MEMFUNC, typename OBJPARSER, typename... PARSER>
665+
class ApplyMemberFunction {
666+
static_assert(std::is_member_function_pointer_v<MEMFUNC>);
667+
using funcType = MEMFUNC;
678668

679669
public:
680-
using resultType = typename OBJPARSER::resultType;
670+
using resultType =
671+
std::invoke_result_t<MEMFUNC, typename OBJPARSER::resultType, PARSER...>;
672+
681673
constexpr ApplyMemberFunction(const ApplyMemberFunction &) = default;
682-
constexpr ApplyMemberFunction(funcType f, OBJPARSER o, PARSER... p)
674+
constexpr ApplyMemberFunction(MEMFUNC f, OBJPARSER o, PARSER... p)
683675
: function_{f}, parsers_{o, p...} {}
684676
std::optional<resultType> Parse(ParseState &state) const {
685677
ApplyArgs<OBJPARSER, PARSER...> results;
686678
using Sequence1 = std::index_sequence_for<OBJPARSER, PARSER...>;
687679
using Sequence2 = std::index_sequence_for<PARSER...>;
688680
if (ApplyHelperArgs(parsers_, results, state, Sequence1{})) {
689-
return ApplyHelperMember<OBJPARSER, PARSER...>(
681+
return ApplyHelperMember<MEMFUNC, OBJPARSER, PARSER...>(
690682
function_, std::move(results), Sequence2{});
691683
} else {
692684
return std::nullopt;
@@ -698,11 +690,11 @@ template <typename OBJPARSER, typename... PARSER> class ApplyMemberFunction {
698690
const std::tuple<OBJPARSER, PARSER...> parsers_;
699691
};
700692

701-
template <typename OBJPARSER, typename... PARSER>
693+
template <typename MEMFUNC, typename OBJPARSER, typename... PARSER>
702694
inline constexpr auto applyMem(
703-
ApplicableMemberFunctionPointer<OBJPARSER, PARSER...> mfp,
704-
const OBJPARSER &objParser, PARSER... parser) {
705-
return ApplyMemberFunction<OBJPARSER, PARSER...>{mfp, objParser, parser...};
695+
MEMFUNC memfn, const OBJPARSER &objParser, PARSER... parser) {
696+
return ApplyMemberFunction<MEMFUNC, OBJPARSER, PARSER...>{
697+
memfn, objParser, parser...};
706698
}
707699

708700
// As is done with function application via applyFunction() above, class

flang/lib/Parser/openmp-parsers.cpp

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,83 @@ static TypeDeclarationStmt makeIterSpecDecl(std::list<ObjectName> &&names) {
153153
makeEntityList(std::move(names)));
154154
}
155155

156+
// --- Parsers for context traits -------------------------------------
157+
158+
static std::string nameToString(Name &&name) { return name.ToString(); }
159+
160+
TYPE_PARSER(sourced(construct<OmpTraitPropertyName>( //
161+
(space >> charLiteralConstantWithoutKind) ||
162+
applyFunction(nameToString, Parser<Name>{}))))
163+
164+
TYPE_PARSER(sourced(construct<OmpTraitScore>( //
165+
"SCORE" >> parenthesized(scalarIntExpr))))
166+
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>( //
176+
Parser<OmpTraitPropertyName>{},
177+
parenthesized(nonemptySeparated(
178+
Parser<OmpTraitPropertyExtension::ExtensionValue>{}, ","_tok)))))
179+
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))))
186+
187+
TYPE_PARSER(construct<OmpTraitSelectorName::Value>(
188+
"ARCH" >> pure(OmpTraitSelectorName::Value::Arch) ||
189+
"ATOMIC_DEFAULT_MEM_ORDER" >>
190+
pure(OmpTraitSelectorName::Value::Atomic_Default_Mem_Order) ||
191+
"CONDITION" >> pure(OmpTraitSelectorName::Value::Condition) ||
192+
"DEVICE_NUM" >> pure(OmpTraitSelectorName::Value::Device_Num) ||
193+
"EXTENSION" >> pure(OmpTraitSelectorName::Value::Extension) ||
194+
"ISA" >> pure(OmpTraitSelectorName::Value::Isa) ||
195+
"KIND" >> pure(OmpTraitSelectorName::Value::Kind) ||
196+
"REQUIRES" >> pure(OmpTraitSelectorName::Value::Requires) ||
197+
"SIMD" >> pure(OmpTraitSelectorName::Value::Simd) ||
198+
"UID" >> pure(OmpTraitSelectorName::Value::Uid) ||
199+
"VENDOR" >> pure(OmpTraitSelectorName::Value::Vendor)))
200+
201+
TYPE_PARSER(sourced(construct<OmpTraitSelectorName>(
202+
// Parse predefined names first (because of SIMD).
203+
construct<OmpTraitSelectorName>(Parser<OmpTraitSelectorName::Value>{}) ||
204+
construct<OmpTraitSelectorName>(OmpDirectiveNameParser{}))))
205+
206+
TYPE_PARSER(construct<OmpTraitSelector::Properties>(
207+
maybe(Parser<OmpTraitScore>{} / ":"_tok),
208+
nonemptySeparated(Parser<OmpTraitProperty>{}, ","_tok)))
209+
210+
TYPE_PARSER(sourced(construct<OmpTraitSelector>( //
211+
Parser<OmpTraitSelectorName>{}, //
212+
maybe(parenthesized(Parser<OmpTraitSelector::Properties>{})))))
213+
214+
TYPE_PARSER(construct<OmpTraitSetSelectorName::Value>(
215+
"CONSTRUCT" >> pure(OmpTraitSetSelectorName::Value::Construct) ||
216+
"DEVICE" >> pure(OmpTraitSetSelectorName::Value::Device) ||
217+
"IMPLEMENTATION" >> pure(OmpTraitSetSelectorName::Value::Implementation) ||
218+
"TARGET_DEVICE" >> pure(OmpTraitSetSelectorName::Value::Target_Device) ||
219+
"USER" >> pure(OmpTraitSetSelectorName::Value::User)))
220+
221+
TYPE_PARSER(sourced(construct<OmpTraitSetSelectorName>(
222+
Parser<OmpTraitSetSelectorName::Value>{})))
223+
224+
TYPE_PARSER(sourced(construct<OmpTraitSetSelector>( //
225+
Parser<OmpTraitSetSelectorName>{},
226+
"=" >> braced(nonemptySeparated(Parser<OmpTraitSelector>{}, ","_tok)))))
227+
228+
TYPE_PARSER(sourced(construct<OmpContextSelectorSpecification>(
229+
nonemptySeparated(Parser<OmpTraitSetSelector>{}, ","_tok))))
230+
231+
// Parser<OmpContextSelector> == Parser<traits::OmpContextSelectorSpecification>
232+
156233
// --- Parsers for clause modifiers -----------------------------------
157234

158235
TYPE_PARSER(construct<OmpAlignment>(scalarIntExpr))

flang/lib/Parser/token-parsers.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,10 @@ template <class PA> inline constexpr auto bracketed(const PA &p) {
215215
return "[" >> p / "]";
216216
}
217217

218+
template <class PA> inline constexpr auto braced(const PA &p) {
219+
return "{" >> p / "}";
220+
}
221+
218222
// Quoted character literal constants.
219223
struct CharLiteralChar {
220224
using resultType = std::pair<char, bool /* was escaped */>;

0 commit comments

Comments
 (0)