@@ -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+
34773624inline 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
0 commit comments