[flang][OpenMP] Version-dependent parsing of map-type-modifier

Up until 5.2, ALWAYS, CLOSE, and PRESENT were keywords of the
map-type-modifier. Starting from 6.0 they all became their own
single-keyword modifiers. This allowed specifying them together,
unlike in the past where map-type-modifier was unique.

To avoid using a single representation of the modifiers, and be
able to validate them through non-conditional properties, the
AST was rewritten back to the older form in canonicalization
when the spec version was set to 5.2 or earlier.

Now that the parser is version-aware, it can generate the desired
AST from the start.

Additionally, extract the OMPX_HOLD modifier out of the map-type-
modifier into its own AST node regardless of version.
This commit is contained in:
Krzysztof Parzyszek 2026-07-31 13:47:50 -05:00
parent cf5e8828dc
commit ce1c15a062
6 changed files with 75 additions and 78 deletions

View file

@ -4212,9 +4212,8 @@ struct OmpMapType {
// CLOSE | // since 5.0, until 5.2
// PRESENT // since 5.1, until 5.2
// Since 6.0 the map-type-modifier has been split into individual modifiers.
//
struct OmpMapTypeModifier {
ENUM_CLASS(Value, Always, Close, Present, Ompx_Hold)
ENUM_CLASS(Value, Always, Close, Present)
WRAPPER_CLASS_BOILERPLATE(OmpMapTypeModifier, Value);
};

View file

@ -1229,7 +1229,6 @@ Map make(const parser::OmpClause::Map &inp,
// clang-format off
MS(Always, Always)
MS(Close, Close)
MS(Ompx_Hold, OmpxHold)
MS(Present, Present)
// clang-format on
);

View file

@ -937,14 +937,55 @@ TYPE_PARSER(construct<OmpMapper>( //
"MAPPER"_tok >> parenthesized(Parser<ObjectName>{})))
// map-type -> ALLOC | DELETE | FROM | RELEASE | STORAGE | TO | TOFROM
TYPE_PARSER(construct<OmpMapType>( //
"ALLOC" >> pure(OmpMapType::Value::Alloc) ||
// Parse "DELETE" as OmpDeleteModifier
"FROM" >> pure(OmpMapType::Value::From) ||
"RELEASE" >> pure(OmpMapType::Value::Release) ||
"STORAGE" >> pure(OmpMapType::Value::Storage) ||
"TO"_id >> pure(OmpMapType::Value::To) ||
"TOFROM" >> pure(OmpMapType::Value::Tofrom)))
struct OmpMapTypeParser {
using resultType = OmpMapType::Value;
std::optional<resultType> Parse(ParseState &state) const {
unsigned version{state.userState()->langOptions().OpenMPVersion};
if (version < 60) {
auto parser{//
"ALLOC" >> pure(OmpMapType::Value::Alloc) ||
"DELETE" >> pure(OmpMapType::Value::Delete) ||
"FROM" >> pure(OmpMapType::Value::From) ||
"RELEASE" >> pure(OmpMapType::Value::Release) ||
"STORAGE" >> pure(OmpMapType::Value::Storage) ||
"TO"_id >> pure(OmpMapType::Value::To) ||
"TOFROM" >> pure(OmpMapType::Value::Tofrom)};
return parser.Parse(state);
} else {
auto parser{//
"ALLOC" >> pure(OmpMapType::Value::Alloc) ||
"FROM" >> pure(OmpMapType::Value::From) ||
"RELEASE" >> pure(OmpMapType::Value::Release) ||
"STORAGE" >> pure(OmpMapType::Value::Storage) ||
"TO"_id >> pure(OmpMapType::Value::To) ||
"TOFROM" >> pure(OmpMapType::Value::Tofrom)};
return parser.Parse(state);
}
}
};
TYPE_PARSER(OmpMapTypeParser{})
struct OmpMapTypeModifierParser {
using resultType = OmpMapTypeModifier::Value;
std::optional<resultType> Parse(ParseState &state) const {
unsigned version{state.userState()->langOptions().OpenMPVersion};
if (version < 60) {
auto parser{//
"ALWAYS" >> pure(OmpMapTypeModifier::Value::Always) ||
"CLOSE" >> pure(OmpMapTypeModifier::Value::Close) ||
"PRESENT" >> pure(OmpMapTypeModifier::Value::Present)};
return parser.Parse(state);
} else {
// No longer in 6.0.
return std::nullopt;
}
}
};
TYPE_PARSER(OmpMapTypeModifierParser{})
TYPE_PARSER(construct<OmpOrderModifier>(
"REPRODUCIBLE" >> pure(OmpOrderModifier::Value::Reproducible) ||
@ -1074,17 +1115,19 @@ TYPE_PARSER(sourced(
construct<OmpLinearClause::Modifier>(Parser<OmpStepSimpleModifier>{})))
TYPE_PARSER(sourced(construct<OmpMapClause::Modifier>(
sourced(construct<OmpMapClause::Modifier>(Parser<OmpAlwaysModifier>{}) ||
construct<OmpMapClause::Modifier>(Parser<OmpAttachModifier>{}) ||
construct<OmpMapClause::Modifier>(Parser<OmpCloseModifier>{}) ||
construct<OmpMapClause::Modifier>(Parser<OmpDeleteModifier>{}) ||
construct<OmpMapClause::Modifier>(Parser<OmpPresentModifier>{}) ||
construct<OmpMapClause::Modifier>(Parser<OmpRefModifier>{}) ||
construct<OmpMapClause::Modifier>(Parser<OmpSelfModifier>{}) ||
construct<OmpMapClause::Modifier>(Parser<OmpMapper>{}) ||
construct<OmpMapClause::Modifier>(Parser<OmpIterator>{}) ||
construct<OmpMapClause::Modifier>(Parser<OmpMapType>{}) ||
construct<OmpMapClause::Modifier>(Parser<OmpxHoldModifier>{})))))
// Try the two custom parsers first.
construct<OmpMapClause::Modifier>(OmpMapTypeParser{}) ||
construct<OmpMapClause::Modifier>(OmpMapTypeModifierParser{}) ||
construct<OmpMapClause::Modifier>(Parser<OmpAlwaysModifier>{}) ||
construct<OmpMapClause::Modifier>(Parser<OmpAttachModifier>{}) ||
construct<OmpMapClause::Modifier>(Parser<OmpCloseModifier>{}) ||
construct<OmpMapClause::Modifier>(Parser<OmpDeleteModifier>{}) ||
construct<OmpMapClause::Modifier>(Parser<OmpIterator>{}) ||
construct<OmpMapClause::Modifier>(Parser<OmpMapper>{}) ||
construct<OmpMapClause::Modifier>(Parser<OmpPresentModifier>{}) ||
construct<OmpMapClause::Modifier>(Parser<OmpRefModifier>{}) ||
construct<OmpMapClause::Modifier>(Parser<OmpSelfModifier>{}) ||
construct<OmpMapClause::Modifier>(Parser<OmpxHoldModifier>{}))))
TYPE_PARSER(
sourced(construct<OmpOrderClause::Modifier>(Parser<OmpOrderModifier>{})))

View file

@ -26,7 +26,7 @@ public:
template <typename T> bool Pre(T &) { return true; }
template <typename T> void Post(T &) {}
CanonicalizationOfOmp(SemanticsContext &context)
: context_{context}, messages_{context.messages()} {}
: messages_{context.messages()} {}
// Pre-visit all constructs that have both a specification part and
// an execution part, and store the connection between the two.
@ -66,8 +66,6 @@ public:
CanonicalizeAllocateDirectives(spec);
}
void Post(parser::OmpMapClause &map) { CanonicalizeMapModifiers(map); }
private:
// Canonicalization of allocate directives
//
@ -325,52 +323,10 @@ private:
omps.erase(rlast.base(), omps.end());
}
// Map clause modifiers are parsed as per OpenMP 6.0 spec. That spec has
// changed properties of some of the modifiers, for example it has expanded
// map-type-modifier into 3 individual modifiers (one for each of the
// possible values of the original modifier), and the "map-type" modifier
// is no longer ultimate.
// To utilize the modifier validation framework for semantic checks,
// if the specified OpenMP version is less than 6.0, rewrite the affected
// modifiers back into the pre-6.0 forms.
void CanonicalizeMapModifiers(parser::OmpMapClause &map) {
unsigned version{context_.langOptions().OpenMPVersion};
if (version >= 60) {
return;
}
// Omp{Always, Close, Present, xHold}Modifier -> OmpMapTypeModifier
// OmpDeleteModifier -> OmpMapType
using Modifier = parser::OmpMapClause::Modifier;
using Modifiers = std::optional<std::list<Modifier>>;
auto &modifiers{std::get<Modifiers>(map.t)};
if (!modifiers) {
return;
}
using MapTypeModifier = parser::OmpMapTypeModifier;
using MapType = parser::OmpMapType;
for (auto &mod : *modifiers) {
if (std::holds_alternative<parser::OmpAlwaysModifier>(mod.u)) {
mod.u = MapTypeModifier(MapTypeModifier::Value::Always);
} else if (std::holds_alternative<parser::OmpCloseModifier>(mod.u)) {
mod.u = MapTypeModifier(MapTypeModifier::Value::Close);
} else if (std::holds_alternative<parser::OmpPresentModifier>(mod.u)) {
mod.u = MapTypeModifier(MapTypeModifier::Value::Present);
} else if (std::holds_alternative<parser::OmpxHoldModifier>(mod.u)) {
mod.u = MapTypeModifier(MapTypeModifier::Value::Ompx_Hold);
} else if (std::holds_alternative<parser::OmpDeleteModifier>(mod.u)) {
mod.u = MapType(MapType::Value::Delete);
}
}
}
// Mapping from the specification parts to the blocks that follow in the
// same construct. This is for converting utility constructs to executable
// constructs.
std::map<parser::SpecificationPart *, parser::Block *> blockForSpec_;
SemanticsContext &context_;
parser::Messages &messages_;
};

View file

@ -1,5 +1,5 @@
!RUN: %flang_fc1 -fdebug-unparse-no-sema -fopenmp -fopenmp-version=60 %s | FileCheck --ignore-case --check-prefix="UNPARSE" %s
!RUN: %flang_fc1 -fdebug-dump-parse-tree-no-sema -fopenmp -fopenmp-version=60 %s | FileCheck --check-prefix="PARSE-TREE" %s
!RUN: %flang_fc1 -fdebug-unparse -fopenmp -fopenmp-version=60 %s | FileCheck --ignore-case --check-prefix="UNPARSE" %s
!RUN: %flang_fc1 -fdebug-dump-parse-tree -fopenmp -fopenmp-version=60 %s | FileCheck --check-prefix="PARSE-TREE" %s
subroutine f00(x)
integer :: x
@ -11,7 +11,7 @@ end
!UNPARSE: SUBROUTINE f00 (x)
!UNPARSE: INTEGER x
!UNPARSE: !$OMP TARGET MAP(ALWAYS, CLOSE, DELETE, PRESENT, OMPX_HOLD: x)
!UNPARSE: x = x+1
!UNPARSE: x=x+1_4
!UNPARSE: !$OMP END TARGET
!UNPARSE: END SUBROUTINE
@ -34,7 +34,7 @@ subroutine f01(x)
end
!UNPARSE: !$OMP TARGET MAP(SELF, STORAGE: x)
!UNPARSE: x = x+1
!UNPARSE: x=x+1_4
!UNPARSE: !$OMP END TARGET
!UNPARSE: END SUBROUTINE
@ -56,7 +56,7 @@ end
!UNPARSE: SUBROUTINE f02 (x)
!UNPARSE: INTEGER, POINTER :: x
!UNPARSE: !$OMP TARGET MAP(REF_PTR, TO: x)
!UNPARSE: x = x+1
!UNPARSE: x=x+1_4
!UNPARSE: !$OMP END TARGET
!UNPARSE: END SUBROUTINE
@ -78,7 +78,7 @@ end
!UNPARSE: SUBROUTINE f03 (x)
!UNPARSE: INTEGER, POINTER :: x
!UNPARSE: !$OMP TARGET MAP(REF_PTEE, TO: x)
!UNPARSE: x = x+1
!UNPARSE: x=x+1_4
!UNPARSE: !$OMP END TARGET
!UNPARSE: END SUBROUTINE
@ -100,7 +100,7 @@ end
!UNPARSE: SUBROUTINE f04 (x)
!UNPARSE: INTEGER, POINTER :: x
!UNPARSE: !$OMP TARGET MAP(REF_PTR_PTEE, TO: x)
!UNPARSE: x = x+1
!UNPARSE: x=x+1_4
!UNPARSE: !$OMP END TARGET
!UNPARSE: END SUBROUTINE

View file

@ -18,7 +18,7 @@ end
!PARSE-TREE: OmpBeginDirective
!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = target
!PARSE-TREE: | OmpClauseList -> OmpClause -> Map -> OmpMapClause
!PARSE-TREE: | | Modifier -> OmpMapTypeModifier -> Value = Ompx_Hold
!PARSE-TREE: | | Modifier -> OmpxHoldModifier -> Value = Ompx_Hold
!PARSE-TREE: | | Modifier -> OmpMapTypeModifier -> Value = Always
!PARSE-TREE: | | Modifier -> OmpMapTypeModifier -> Value = Present
!PARSE-TREE: | | Modifier -> OmpMapTypeModifier -> Value = Close
@ -43,7 +43,7 @@ end
!PARSE-TREE: OmpBeginDirective
!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = target
!PARSE-TREE: | OmpClauseList -> OmpClause -> Map -> OmpMapClause
!PARSE-TREE: | | Modifier -> OmpMapTypeModifier -> Value = Ompx_Hold
!PARSE-TREE: | | Modifier -> OmpxHoldModifier -> Value = Ompx_Hold
!PARSE-TREE: | | Modifier -> OmpMapTypeModifier -> Value = Always
!PARSE-TREE: | | Modifier -> OmpMapTypeModifier -> Value = Present
!PARSE-TREE: | | Modifier -> OmpMapTypeModifier -> Value = Close
@ -108,7 +108,7 @@ end
!PARSE-TREE: OmpBeginDirective
!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = target
!PARSE-TREE: | OmpClauseList -> OmpClause -> Map -> OmpMapClause
!PARSE-TREE: | | Modifier -> OmpMapTypeModifier -> Value = Ompx_Hold
!PARSE-TREE: | | Modifier -> OmpxHoldModifier -> Value = Ompx_Hold
!PARSE-TREE: | | Modifier -> OmpMapTypeModifier -> Value = Always
!PARSE-TREE: | | Modifier -> OmpMapTypeModifier -> Value = Present
!PARSE-TREE: | | Modifier -> OmpMapTypeModifier -> Value = Close
@ -133,7 +133,7 @@ end
!PARSE-TREE: OmpBeginDirective
!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = target
!PARSE-TREE: | OmpClauseList -> OmpClause -> Map -> OmpMapClause
!PARSE-TREE: | | Modifier -> OmpMapTypeModifier -> Value = Ompx_Hold
!PARSE-TREE: | | Modifier -> OmpxHoldModifier -> Value = Ompx_Hold
!PARSE-TREE: | | Modifier -> OmpMapTypeModifier -> Value = Always
!PARSE-TREE: | | Modifier -> OmpMapTypeModifier -> Value = Present
!PARSE-TREE: | | Modifier -> OmpMapTypeModifier -> Value = Close