[llvm-branch-commits] [flang] [flang][OpenMP] Handle directive arguments in OmpDirectiveSpecifier (PR #124278)
Krzysztof Parzyszek via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Fri Jan 24 06:43:40 PST 2025
https://github.com/kparzysz created https://github.com/llvm/llvm-project/pull/124278
Implement parsing and symbol resolution for directives that take arguments. There are a few, and most of them take objects. Special handling is needed for two that take more specialized arguments: DECLARE MAPPER and DECLARE REDUCTION.
This only affects directives in METADIRECTIVE's WHEN and OTHERWISE clauses. Parsing and semantic checks of other cases is unaffected.
>From e230e8ad3bcd09fc28b18f64a84fcd20d6e9bc65 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Wed, 22 Jan 2025 09:47:44 -0600
Subject: [PATCH] [flang][OpenMP] Handle directive arguments in
OmpDirectiveSpecifier
Implement parsing and symbol resolution for directives that take
arguments. There are a few, and most of them take objects. Special
handling is needed for two that take more specialized arguments:
DECLARE MAPPER and DECLARE REDUCTION.
This only affects directives in METADIRECTIVE's WHEN and OTHERWISE
clauses. Parsing and semantic checks of other cases is unaffected.
---
flang/examples/FeatureList/FeatureList.cpp | 1 -
flang/include/flang/Parser/dump-parse-tree.h | 9 +-
flang/include/flang/Parser/parse-tree.h | 142 ++++++----
flang/lib/Parser/openmp-parsers.cpp | 68 +++--
flang/lib/Parser/unparse.cpp | 40 +--
flang/lib/Semantics/check-omp-structure.cpp | 2 +-
flang/lib/Semantics/resolve-names.cpp | 130 +++++++---
.../Parser/OpenMP/declare-mapper-unparse.f90 | 4 +-
.../Parser/OpenMP/metadirective-dirspec.f90 | 242 ++++++++++++++++++
9 files changed, 517 insertions(+), 121 deletions(-)
create mode 100644 flang/test/Parser/OpenMP/metadirective-dirspec.f90
diff --git a/flang/examples/FeatureList/FeatureList.cpp b/flang/examples/FeatureList/FeatureList.cpp
index 3a689c335c81c0..e35f120d8661ea 100644
--- a/flang/examples/FeatureList/FeatureList.cpp
+++ b/flang/examples/FeatureList/FeatureList.cpp
@@ -514,7 +514,6 @@ struct NodeVisitor {
READ_FEATURE(OmpReductionClause)
READ_FEATURE(OmpInReductionClause)
READ_FEATURE(OmpReductionCombiner)
- READ_FEATURE(OmpReductionCombiner::FunctionCombiner)
READ_FEATURE(OmpReductionInitializerClause)
READ_FEATURE(OmpReductionIdentifier)
READ_FEATURE(OmpAllocateClause)
diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h
index 1323fd695d4439..ce518c7c3edea0 100644
--- a/flang/include/flang/Parser/dump-parse-tree.h
+++ b/flang/include/flang/Parser/dump-parse-tree.h
@@ -476,6 +476,12 @@ class ParseTreeDumper {
NODE(parser, NullInit)
NODE(parser, ObjectDecl)
NODE(parser, OldParameterStmt)
+ NODE(parser, OmpTypeSpecifier)
+ NODE(parser, OmpTypeNameList)
+ NODE(parser, OmpLocator)
+ NODE(parser, OmpLocatorList)
+ NODE(parser, OmpReductionSpecifier)
+ NODE(parser, OmpArgument)
NODE(parser, OmpMetadirectiveDirective)
NODE(parser, OmpMatchClause)
NODE(parser, OmpOtherwiseClause)
@@ -541,7 +547,7 @@ class ParseTreeDumper {
NODE(parser, OmpDeclareTargetSpecifier)
NODE(parser, OmpDeclareTargetWithClause)
NODE(parser, OmpDeclareTargetWithList)
- NODE(parser, OmpDeclareMapperSpecifier)
+ NODE(parser, OmpMapperSpecifier)
NODE(parser, OmpDefaultClause)
NODE_ENUM(OmpDefaultClause, DataSharingAttribute)
NODE(parser, OmpVariableCategory)
@@ -624,7 +630,6 @@ class ParseTreeDumper {
NODE(parser, OmpReductionCombiner)
NODE(parser, OmpTaskReductionClause)
NODE(OmpTaskReductionClause, Modifier)
- NODE(OmpReductionCombiner, FunctionCombiner)
NODE(parser, OmpReductionInitializerClause)
NODE(parser, OmpReductionIdentifier)
NODE(parser, OmpAllocateClause)
diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index 2e27b6ea7eafa1..993c1338f7235b 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -3454,15 +3454,7 @@ WRAPPER_CLASS(PauseStmt, std::optional<StopCode>);
// --- Common definitions
struct OmpClause;
-struct OmpClauseList;
-
-struct OmpDirectiveSpecification {
- TUPLE_CLASS_BOILERPLATE(OmpDirectiveSpecification);
- std::tuple<llvm::omp::Directive,
- std::optional<common::Indirection<OmpClauseList>>>
- t;
- CharBlock source;
-};
+struct OmpDirectiveSpecification;
// 2.1 Directives or clauses may accept a list or extended-list.
// A list item is a variable, array section or common block name (enclosed
@@ -3475,15 +3467,76 @@ struct OmpObject {
WRAPPER_CLASS(OmpObjectList, std::list<OmpObject>);
-#define MODIFIER_BOILERPLATE(...) \
- struct Modifier { \
- using Variant = std::variant<__VA_ARGS__>; \
- UNION_CLASS_BOILERPLATE(Modifier); \
- CharBlock source; \
- Variant u; \
- }
+// Ref: [4.5:201-207], [5.0:293-299], [5.1:325-331], [5.2:124]
+//
+// reduction-identifier ->
+// base-language-identifier | // since 4.5
+// - | // since 4.5, until 5.2
+// + | * | .AND. | .OR. | .EQV. | .NEQV. | // since 4.5
+// MIN | MAX | IAND | IOR | IEOR // since 4.5
+struct OmpReductionIdentifier {
+ UNION_CLASS_BOILERPLATE(OmpReductionIdentifier);
+ std::variant<DefinedOperator, ProcedureDesignator> u;
+};
-#define MODIFIERS() std::optional<std::list<Modifier>>
+// Ref: [4.5:222:6], [5.0:305:27], [5.1:337:19], [5.2:126:3-4], [6.0:240:27-28]
+//
+// combiner-expression -> // since 4.5
+// assignment-statement |
+// function-reference
+struct OmpReductionCombiner {
+ UNION_CLASS_BOILERPLATE(OmpReductionCombiner);
+ std::variant<AssignmentStmt, FunctionReference> u;
+};
+
+inline namespace arguments {
+struct OmpTypeSpecifier {
+ UNION_CLASS_BOILERPLATE(OmpTypeSpecifier);
+ std::variant<TypeSpec, DeclarationTypeSpec> u;
+};
+
+WRAPPER_CLASS(OmpTypeNameList, std::list<OmpTypeSpecifier>);
+
+struct OmpLocator {
+ UNION_CLASS_BOILERPLATE(OmpLocator);
+ std::variant<OmpObject, FunctionReference> u;
+};
+
+WRAPPER_CLASS(OmpLocatorList, std::list<OmpLocator>);
+
+// Ref: [5.0:326:10-16], [5.1:359:5-11], [5.2:163:2-7], [6.0:293:16-21]
+//
+// mapper-specifier ->
+// [mapper-identifier :] type :: var | // since 5.0
+// DEFAULT type :: var
+struct OmpMapperSpecifier {
+ // Absent mapper-identifier is equivalent to DEFAULT.
+ TUPLE_CLASS_BOILERPLATE(OmpMapperSpecifier);
+ std::tuple<std::optional<Name>, TypeSpec, Name> t;
+};
+
+// Ref: [4.5:222:1-5], [5.0:305:20-27], [5.1:337:11-19], [5.2:139:18-23],
+// [6.0:260:16-20]
+//
+// reduction-specifier ->
+// reduction-identifier : typename-list
+// : combiner-expression // since 4.5, until 5.2
+// reduction-identifier : typename-list // since 6.0
+struct OmpReductionSpecifier {
+ TUPLE_CLASS_BOILERPLATE(OmpReductionSpecifier);
+ std::tuple<OmpReductionIdentifier, OmpTypeNameList,
+ std::optional<OmpReductionCombiner>>
+ t;
+};
+
+struct OmpArgument {
+ CharBlock source;
+ UNION_CLASS_BOILERPLATE(OmpArgument);
+ std::variant<OmpLocator, // {variable, extended, locator}-list-item
+ OmpMapperSpecifier, OmpReductionSpecifier>
+ u;
+};
+} // namespace arguments
inline namespace traits {
// trait-property-name ->
@@ -3617,6 +3670,16 @@ struct OmpContextSelectorSpecification { // Modifier
};
} // namespace traits
+#define MODIFIER_BOILERPLATE(...) \
+ struct Modifier { \
+ using Variant = std::variant<__VA_ARGS__>; \
+ UNION_CLASS_BOILERPLATE(Modifier); \
+ CharBlock source; \
+ Variant u; \
+ }
+
+#define MODIFIERS() std::optional<std::list<Modifier>>
+
inline namespace modifier {
// For uniformity, in all keyword modifiers the name of the type defined
// by ENUM_CLASS is "Value", e.g.
@@ -3829,18 +3892,6 @@ struct OmpPrescriptiveness {
WRAPPER_CLASS_BOILERPLATE(OmpPrescriptiveness, Value);
};
-// Ref: [4.5:201-207], [5.0:293-299], [5.1:325-331], [5.2:124]
-//
-// reduction-identifier ->
-// base-language-identifier | // since 4.5
-// - | // since 4.5, until 5.2
-// + | * | .AND. | .OR. | .EQV. | .NEQV. | // since 4.5
-// MIN | MAX | IAND | IOR | IEOR // since 4.5
-struct OmpReductionIdentifier {
- UNION_CLASS_BOILERPLATE(OmpReductionIdentifier);
- std::variant<DefinedOperator, ProcedureDesignator> u;
-};
-
// Ref: [5.0:300-302], [5.1:332-334], [5.2:134-137]
//
// reduction-modifier ->
@@ -3983,7 +4034,9 @@ struct OmpBindClause {
struct OmpDefaultClause {
ENUM_CLASS(DataSharingAttribute, Private, Firstprivate, Shared, None)
UNION_CLASS_BOILERPLATE(OmpDefaultClause);
- std::variant<DataSharingAttribute, OmpDirectiveSpecification> u;
+ std::variant<DataSharingAttribute,
+ common::Indirection<OmpDirectiveSpecification>>
+ u;
};
// Ref: [4.5:103-107], [5.0:324-325], [5.1:357-358], [5.2:161-162]
@@ -4248,8 +4301,8 @@ struct OmpOrderClause {
// otherwise-clause ->
// OTHERWISE ([directive-specification])] // since 5.2
struct OmpOtherwiseClause {
- WRAPPER_CLASS_BOILERPLATE(
- OmpOtherwiseClause, std::optional<OmpDirectiveSpecification>);
+ WRAPPER_CLASS_BOILERPLATE(OmpOtherwiseClause,
+ std::optional<common::Indirection<OmpDirectiveSpecification>>);
};
// Ref: [4.5:46-50], [5.0:74-78], [5.1:92-96], [5.2:229-230]
@@ -4345,7 +4398,9 @@ struct OmpUpdateClause {
struct OmpWhenClause {
TUPLE_CLASS_BOILERPLATE(OmpWhenClause);
MODIFIER_BOILERPLATE(OmpContextSelector);
- std::tuple<MODIFIERS(), std::optional<OmpDirectiveSpecification>> t;
+ std::tuple<MODIFIERS(),
+ std::optional<common::Indirection<OmpDirectiveSpecification>>>
+ t;
};
// OpenMP Clauses
@@ -4372,6 +4427,14 @@ struct OmpClauseList {
// --- Directives and constructs
+struct OmpDirectiveSpecification {
+ CharBlock source;
+ TUPLE_CLASS_BOILERPLATE(OmpDirectiveSpecification);
+ std::tuple<llvm::omp::Directive, std::optional<std::list<OmpArgument>>,
+ std::optional<OmpClauseList>>
+ t;
+};
+
struct OmpMetadirectiveDirective {
TUPLE_CLASS_BOILERPLATE(OmpMetadirectiveDirective);
std::tuple<OmpClauseList> t;
@@ -4472,27 +4535,16 @@ struct OpenMPDeclareTargetConstruct {
std::tuple<Verbatim, OmpDeclareTargetSpecifier> t;
};
-struct OmpDeclareMapperSpecifier {
- TUPLE_CLASS_BOILERPLATE(OmpDeclareMapperSpecifier);
- std::tuple<std::optional<Name>, TypeSpec, Name> t;
-};
-
// OMP v5.2: 5.8.8
// declare-mapper -> DECLARE MAPPER ([mapper-name :] type :: var) map-clauses
struct OpenMPDeclareMapperConstruct {
TUPLE_CLASS_BOILERPLATE(OpenMPDeclareMapperConstruct);
CharBlock source;
- std::tuple<Verbatim, OmpDeclareMapperSpecifier, OmpClauseList> t;
+ std::tuple<Verbatim, OmpMapperSpecifier, OmpClauseList> t;
};
// 2.16 declare-reduction -> DECLARE REDUCTION (reduction-identifier : type-list
// : combiner) [initializer-clause]
-struct OmpReductionCombiner {
- UNION_CLASS_BOILERPLATE(OmpReductionCombiner);
- WRAPPER_CLASS(FunctionCombiner, Call);
- std::variant<AssignmentStmt, FunctionCombiner> u;
-};
-
WRAPPER_CLASS(OmpReductionInitializerClause, Expr);
struct OpenMPDeclareReductionConstruct {
diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp
index f5387dcf4b3c3d..e73e0ac2c85ff9 100644
--- a/flang/lib/Parser/openmp-parsers.cpp
+++ b/flang/lib/Parser/openmp-parsers.cpp
@@ -68,6 +68,8 @@ void OmpDirectiveNameParser::initTokens(NameWithId *table) const {
[](auto &a, auto &b) { return a.first.size() > b.first.size(); });
}
+// --- Modifier helpers -----------------------------------------------
+
template <typename Clause, typename Separator> struct ModifierList {
constexpr ModifierList(Separator sep) : sep_(sep) {}
constexpr ModifierList(const ModifierList &) = default;
@@ -118,10 +120,8 @@ struct SpecificModifierParser {
}
};
-// OpenMP Clauses
+// --- Iterator helpers -----------------------------------------------
-// [5.0] 2.1.6 iterator-specifier -> type-declaration-stmt = subscript-triple |
-// identifier = subscript-triple
// [5.0:47:17-18] In an iterator-specifier, if the iterator-type is not
// specified then the type of that iterator is default integer.
// [5.0:49:14] The iterator-type must be an integer type.
@@ -153,8 +153,30 @@ static TypeDeclarationStmt makeIterSpecDecl(std::list<ObjectName> &&names) {
makeEntityList(std::move(names)));
}
-TYPE_PARSER(sourced(construct<OmpDirectiveSpecification>(
- OmpDirectiveNameParser{}, maybe(indirect(Parser<OmpClauseList>{})))))
+// --- Parsers for arguments ------------------------------------------
+
+// At the moment these are only directive arguments. This is needed for
+// parsing directive-specification.
+
+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<OmpLocatorList>(nonemptyList(Parser<OmpLocator>{})))
+
+TYPE_PARSER( //
+ construct<OmpTypeSpecifier>(Parser<TypeSpec>{}) ||
+ construct<OmpTypeSpecifier>(Parser<DeclarationTypeSpec>{}))
+
+TYPE_PARSER(construct<OmpReductionSpecifier>( //
+ Parser<OmpReductionIdentifier>{},
+ ":"_tok >> nonemptyList(Parser<OmpTypeSpecifier>{}),
+ maybe(":"_tok >> Parser<OmpReductionCombiner>{})))
// --- Parsers for context traits -------------------------------------
@@ -213,15 +235,11 @@ static constexpr auto propertyListParser(PropParser... pp) {
// the entire list in each of the alternative property parsers. Otherwise,
// the name parser could stop after "foo" in "(foo, bar(1))", without
// allowing the next parser to give the list a try.
- auto listOf{[](auto parser) { //
- return nonemptySeparated(parser, ",");
- }};
-
using P = OmpTraitProperty;
return maybe("(" >> //
construct<OmpTraitSelector::Properties>(
maybe(Parser<OmpTraitScore>{} / ":"),
- (attempt(listOf(sourced(construct<P>(pp))) / ")") || ...)));
+ (attempt(nonemptyList(sourced(construct<P>(pp))) / ")") || ...)));
}
// Parser for OmpTraitSelector
@@ -309,7 +327,7 @@ TYPE_PARSER(sourced(construct<OmpTraitSetSelector>( //
TYPE_PARSER(sourced(construct<OmpContextSelectorSpecification>(
nonemptySeparated(Parser<OmpTraitSetSelector>{}, ","))))
-// Parser<OmpContextSelector> == Parser<traits::OmpContextSelectorSpecification>
+// Note: OmpContextSelector is a type alias.
// --- Parsers for clause modifiers -----------------------------------
@@ -543,7 +561,7 @@ TYPE_PARSER(construct<OmpDefaultClause::DataSharingAttribute>(
TYPE_PARSER(construct<OmpDefaultClause>(
construct<OmpDefaultClause>(
Parser<OmpDefaultClause::DataSharingAttribute>{}) ||
- construct<OmpDefaultClause>(Parser<OmpDirectiveSpecification>{})))
+ construct<OmpDefaultClause>(indirect(Parser<OmpDirectiveSpecification>{}))))
// 2.5 PROC_BIND (MASTER | CLOSE | PRIMARY | SPREAD)
TYPE_PARSER(construct<OmpProcBindClause>(
@@ -713,11 +731,11 @@ TYPE_PARSER(construct<OmpMatchClause>(
Parser<traits::OmpContextSelectorSpecification>{}))
TYPE_PARSER(construct<OmpOtherwiseClause>(
- maybe(sourced(Parser<OmpDirectiveSpecification>{}))))
+ maybe(indirect(sourced(Parser<OmpDirectiveSpecification>{})))))
TYPE_PARSER(construct<OmpWhenClause>(
maybe(nonemptyList(Parser<OmpWhenClause::Modifier>{}) / ":"),
- maybe(sourced(Parser<OmpDirectiveSpecification>{}))))
+ maybe(indirect(sourced(Parser<OmpDirectiveSpecification>{})))))
// OMP 5.2 12.6.1 grainsize([ prescriptiveness :] scalar-integer-expression)
TYPE_PARSER(construct<OmpGrainsizeClause>(
@@ -929,6 +947,13 @@ TYPE_PARSER(construct<OmpObjectList>(nonemptyList(Parser<OmpObject>{})))
TYPE_PARSER(sourced(construct<OmpErrorDirective>(
verbatim("ERROR"_tok), Parser<OmpClauseList>{})))
+// --- Parsers for directives and constructs --------------------------
+
+TYPE_PARSER(sourced(construct<OmpDirectiveSpecification>( //
+ OmpDirectiveNameParser{},
+ maybe(parenthesized(nonemptyList(Parser<OmpArgument>{}))),
+ maybe(Parser<OmpClauseList>{}))))
+
TYPE_PARSER(sourced(construct<OmpNothingDirective>("NOTHING" >> ok)))
TYPE_PARSER(sourced(construct<OpenMPUtilityConstruct>(
@@ -1141,20 +1166,17 @@ TYPE_PARSER(
TYPE_PARSER(sourced(construct<OpenMPDeclareTargetConstruct>(
verbatim("DECLARE TARGET"_tok), Parser<OmpDeclareTargetSpecifier>{})))
-// declare-mapper-specifier
-TYPE_PARSER(construct<OmpDeclareMapperSpecifier>(
+// mapper-specifier
+TYPE_PARSER(construct<OmpMapperSpecifier>(
maybe(name / ":" / !":"_tok), typeSpec / "::", name))
// OpenMP 5.2: 5.8.8 Declare Mapper Construct
-TYPE_PARSER(sourced(construct<OpenMPDeclareMapperConstruct>(
- verbatim("DECLARE MAPPER"_tok),
- "(" >> Parser<OmpDeclareMapperSpecifier>{} / ")", Parser<OmpClauseList>{})))
+TYPE_PARSER(sourced(
+ construct<OpenMPDeclareMapperConstruct>(verbatim("DECLARE MAPPER"_tok),
+ parenthesized(Parser<OmpMapperSpecifier>{}), Parser<OmpClauseList>{})))
TYPE_PARSER(construct<OmpReductionCombiner>(Parser<AssignmentStmt>{}) ||
- construct<OmpReductionCombiner>(
- construct<OmpReductionCombiner::FunctionCombiner>(
- construct<Call>(Parser<ProcedureDesignator>{},
- parenthesized(optionalList(actualArgSpec))))))
+ construct<OmpReductionCombiner>(Parser<FunctionReference>{}))
// 2.17.7 atomic -> ATOMIC [clause [,]] atomic-clause [[,] clause] |
// ATOMIC [clause]
diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp
index 7d3b03e5bc27e7..bc1c472f276ea1 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -2067,12 +2067,33 @@ class UnparseVisitor {
}
// OpenMP Clauses & Directives
+ void Unparse(const OmpTypeNameList &x) { //
+ Walk(x.v, ",");
+ }
+ void Unparse(const OmpMapperSpecifier &x) {
+ Walk(std::get<std::optional<Name>>(x.t), ":");
+ Walk(std::get<TypeSpec>(x.t));
+ Put("::");
+ Walk(std::get<Name>(x.t));
+ }
+ void Unparse(const OmpReductionSpecifier &x) {
+ Walk(std::get<OmpReductionIdentifier>(x.t));
+ Put(":");
+ Walk(std::get<OmpTypeNameList>(x.t));
+ Walk(":", std::get<std::optional<OmpReductionCombiner>>(x.t));
+ }
void Unparse(const llvm::omp::Directive &x) {
Word(llvm::omp::getOpenMPDirectiveName(x).str());
}
void Unparse(const OmpDirectiveSpecification &x) {
+ using ArgList = std::list<parser::OmpArgument>;
Walk(std::get<llvm::omp::Directive>(x.t));
- Walk(std::get<std::optional<common::Indirection<OmpClauseList>>>(x.t));
+ if (auto &args{std::get<std::optional<ArgList>>(x.t)}) {
+ Put("(");
+ Walk(*args);
+ Put(")");
+ }
+ Walk(std::get<std::optional<OmpClauseList>>(x.t));
}
void Unparse(const OmpTraitScore &x) {
Word("SCORE(");
@@ -2297,8 +2318,9 @@ class UnparseVisitor {
}
void Unparse(const OmpWhenClause &x) {
using Modifier = OmpWhenClause::Modifier;
+ using Directive = common::Indirection<OmpDirectiveSpecification>;
Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": ");
- Walk(std::get<std::optional<OmpDirectiveSpecification>>(x.t));
+ Walk(std::get<std::optional<Directive>>(x.t));
}
#define GEN_FLANG_CLAUSE_UNPARSE
#include "llvm/Frontend/OpenMP/OMP.inc"
@@ -2660,18 +2682,6 @@ class UnparseVisitor {
Walk(x.v);
Put(")");
}
- void Unparse(const OmpReductionCombiner::FunctionCombiner &x) {
- const auto &pd = std::get<ProcedureDesignator>(x.v.t);
- const auto &args = std::get<std::list<ActualArgSpec>>(x.v.t);
- Walk(pd);
- if (args.empty()) {
- if (std::holds_alternative<ProcComponentRef>(pd.u)) {
- Put("()");
- }
- } else {
- Walk("(", args, ", ", ")");
- }
- }
void Unparse(const OpenMPDeclareReductionConstruct &x) {
BeginOpenMP();
Word("!$OMP DECLARE REDUCTION ");
@@ -2687,7 +2697,7 @@ class UnparseVisitor {
void Unparse(const OpenMPDeclareMapperConstruct &z) {
BeginOpenMP();
Word("!$OMP DECLARE MAPPER (");
- const auto &spec{std::get<OmpDeclareMapperSpecifier>(z.t)};
+ const auto &spec{std::get<OmpMapperSpecifier>(z.t)};
if (auto mapname{std::get<std::optional<Name>>(spec.t)}) {
Walk(mapname);
Put(":");
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 94886d6b9dfdc9..bde97e0b87e565 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -1606,7 +1606,7 @@ void OmpStructureChecker::Enter(const parser::OpenMPDeclareMapperConstruct &x) {
const auto &dir{std::get<parser::Verbatim>(x.t)};
PushContextAndClauseSets(
dir.source, llvm::omp::Directive::OMPD_declare_mapper);
- const auto &spec{std::get<parser::OmpDeclareMapperSpecifier>(x.t)};
+ const auto &spec{std::get<parser::OmpMapperSpecifier>(x.t)};
const auto &type = std::get<parser::TypeSpec>(spec.t);
if (!std::get_if<parser::DerivedTypeSpec>(&type.u)) {
context_.Say(dir.source, "Type is not a derived type"_err_en_US);
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index f3c2a5bf094d04..82bfaa1385fbba 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -1471,7 +1471,12 @@ class OmpVisitor : public virtual DeclarationVisitor {
return true;
}
- bool Pre(const parser::OpenMPDeclareMapperConstruct &);
+ bool Pre(const parser::OpenMPDeclareMapperConstruct &x) {
+ AddOmpSourceRange(x.source);
+ ProcessMapperSpecifier(std::get<parser::OmpMapperSpecifier>(x.t),
+ std::get<parser::OmpClauseList>(x.t));
+ return false;
+ }
bool Pre(const parser::OmpMapClause &);
@@ -1573,6 +1578,21 @@ class OmpVisitor : public virtual DeclarationVisitor {
PopScope();
}
}
+ bool Pre(const parser::OmpDirectiveSpecification &x);
+
+ bool Pre(const parser::OmpTypeSpecifier &x) {
+ BeginDeclTypeSpec();
+ return true;
+ }
+ void Post(const parser::OmpTypeSpecifier &x) { //
+ EndDeclTypeSpec();
+ }
+
+private:
+ void ProcessMapperSpecifier(const parser::OmpMapperSpecifier &spec,
+ const parser::OmpClauseList &clauses);
+ void ProcessReductionSpecifier(const parser::OmpReductionSpecifier &spec,
+ const parser::OmpClauseList &clauses);
};
bool OmpVisitor::NeedsScope(const parser::OpenMPBlockConstruct &x) {
@@ -1612,37 +1632,6 @@ void OmpVisitor::Post(const parser::OpenMPBlockConstruct &x) {
}
}
-// This "manually" walks the tree of the construct, because we need
-// to resolve the type before the map clauses are processed - when
-// just following the natural flow, the map clauses gets processed before
-// the type has been fully processed.
-bool OmpVisitor::Pre(const parser::OpenMPDeclareMapperConstruct &x) {
- AddOmpSourceRange(x.source);
- BeginDeclTypeSpec();
- const auto &spec{std::get<parser::OmpDeclareMapperSpecifier>(x.t)};
- Symbol *mapperSym{nullptr};
- if (const auto &mapperName{std::get<std::optional<parser::Name>>(spec.t)}) {
- mapperSym =
- &MakeSymbol(*mapperName, MiscDetails{MiscDetails::Kind::ConstructName});
- mapperName->symbol = mapperSym;
- } else {
- const parser::CharBlock defaultName{"default", 7};
- mapperSym = &MakeSymbol(
- defaultName, Attrs{}, MiscDetails{MiscDetails::Kind::ConstructName});
- }
-
- PushScope(Scope::Kind::OtherConstruct, nullptr);
- Walk(std::get<parser::TypeSpec>(spec.t));
- const auto &varName{std::get<parser::ObjectName>(spec.t)};
- DeclareObjectEntity(varName);
-
- Walk(std::get<parser::OmpClauseList>(x.t));
-
- EndDeclTypeSpec();
- PopScope();
- return false;
-}
-
bool OmpVisitor::Pre(const parser::OmpMapClause &x) {
auto &mods{OmpGetModifiers(x)};
if (auto *mapper{OmpGetUniqueModifier<parser::OmpMapper>(mods)}) {
@@ -1670,6 +1659,83 @@ bool OmpVisitor::Pre(const parser::OmpMapClause &x) {
return true;
}
+void OmpVisitor::ProcessMapperSpecifier(const parser::OmpMapperSpecifier &spec,
+ const parser::OmpClauseList &clauses) {
+ // This "manually" walks the tree of the construct, because we need
+ // to resolve the type before the map clauses are processed - when
+ // just following the natural flow, the map clauses gets processed before
+ // the type has been fully processed.
+ BeginDeclTypeSpec();
+ if (auto &mapperName{std::get<std::optional<parser::Name>>(spec.t)}) {
+ mapperName->symbol =
+ &MakeSymbol(*mapperName, MiscDetails{MiscDetails::Kind::ConstructName});
+ } else {
+ const parser::CharBlock defaultName{"default", 7};
+ MakeSymbol(
+ defaultName, Attrs{}, MiscDetails{MiscDetails::Kind::ConstructName});
+ }
+
+ PushScope(Scope::Kind::OtherConstruct, nullptr);
+ Walk(std::get<parser::TypeSpec>(spec.t));
+ auto &varName{std::get<parser::Name>(spec.t)};
+ DeclareObjectEntity(varName);
+
+ Walk(clauses);
+ EndDeclTypeSpec();
+ PopScope();
+}
+
+void OmpVisitor::ProcessReductionSpecifier(
+ const parser::OmpReductionSpecifier &spec,
+ const parser::OmpClauseList &clauses) {
+ // Creating a new scope in case the combiner expression (or clauses) use
+ // reerved identifiers, like "omp_in". This is a temporary solution until
+ // we deal with these in a more thorough way.
+ PushScope(Scope::Kind::OtherConstruct, nullptr);
+ Walk(std::get<parser::OmpReductionIdentifier>(spec.t));
+ Walk(std::get<parser::OmpTypeNameList>(spec.t));
+ Walk(std::get<std::optional<parser::OmpReductionCombiner>>(spec.t));
+ Walk(clauses);
+ PopScope();
+}
+
+bool OmpVisitor::Pre(const parser::OmpDirectiveSpecification &x) {
+ // OmpDirectiveSpecification is only used in METADIRECTIVE at the moment.
+ // Since it contains directives and clauses, some semantic checks may
+ // not be applicable.
+ // Disable the semantic analysis for it for now to allow the compiler to
+ // parse METADIRECTIVE without flagging errors.
+ AddOmpSourceRange(x.source);
+ auto dirId{std::get<llvm::omp::Directive>(x.t)};
+ auto &maybeArgs{std::get<std::optional<std::list<parser::OmpArgument>>>(x.t)};
+ auto &maybeClauses{std::get<std::optional<parser::OmpClauseList>>(x.t)};
+
+ switch (dirId) {
+ case llvm::omp::Directive::OMPD_declare_mapper:
+ if (maybeArgs && maybeClauses) {
+ const parser::OmpArgument &first{maybeArgs->front()};
+ if (auto *spec{std::get_if<parser::OmpMapperSpecifier>(&first.u)}) {
+ ProcessMapperSpecifier(*spec, *maybeClauses);
+ }
+ }
+ break;
+ case llvm::omp::Directive::OMPD_declare_reduction:
+ if (maybeArgs && maybeClauses) {
+ const parser::OmpArgument &first{maybeArgs->front()};
+ if (auto *spec{std::get_if<parser::OmpReductionSpecifier>(&first.u)}) {
+ ProcessReductionSpecifier(*spec, *maybeClauses);
+ }
+ }
+ break;
+ default:
+ // Default processing.
+ Walk(maybeArgs);
+ Walk(maybeClauses);
+ break;
+ }
+ return false;
+}
+
// Walk the parse tree and resolve names to symbols.
class ResolveNamesVisitor : public virtual ScopeHandler,
public ModuleVisitor,
diff --git a/flang/test/Parser/OpenMP/declare-mapper-unparse.f90 b/flang/test/Parser/OpenMP/declare-mapper-unparse.f90
index 5ba147d20955e3..407bfd29153fad 100644
--- a/flang/test/Parser/OpenMP/declare-mapper-unparse.f90
+++ b/flang/test/Parser/OpenMP/declare-mapper-unparse.f90
@@ -13,7 +13,7 @@ program main
!$omp declare mapper(mymapper : ty :: mapped) map(mapped, mapped%x)
!PARSE-TREE: OpenMPDeclareMapperConstruct
-!PARSE-TREE: OmpDeclareMapperSpecifier
+!PARSE-TREE: OmpMapperSpecifier
!PARSE-TREE: Name = 'mymapper'
!PARSE-TREE: TypeSpec -> DerivedTypeSpec
!PARSE-TREE: Name = 'ty'
@@ -28,7 +28,7 @@ program main
!$omp declare mapper(ty :: mapped) map(mapped, mapped%x)
!PARSE-TREE: OpenMPDeclareMapperConstruct
-!PARSE-TREE: OmpDeclareMapperSpecifier
+!PARSE-TREE: OmpMapperSpecifier
!PARSE-TREE: TypeSpec -> DerivedTypeSpec
!PARSE-TREE: Name = 'ty'
!PARSE-TREE: Name = 'mapped'
diff --git a/flang/test/Parser/OpenMP/metadirective-dirspec.f90 b/flang/test/Parser/OpenMP/metadirective-dirspec.f90
new file mode 100644
index 00000000000000..73520c41fe77da
--- /dev/null
+++ b/flang/test/Parser/OpenMP/metadirective-dirspec.f90
@@ -0,0 +1,242 @@
+!RUN: %flang_fc1 -fdebug-unparse -fopenmp -fopenmp-version=52 %s | FileCheck --ignore-case --check-prefix="UNPARSE" %s
+!RUN: %flang_fc1 -fdebug-dump-parse-tree -fopenmp -fopenmp-version=52 %s | FileCheck --check-prefix="PARSE-TREE" %s
+
+!Directive specification where directives have arguments
+
+subroutine f00(x)
+ integer :: x(10)
+ !$omp metadirective when(user={condition(.true.)}: &
+ !$omp & allocate(x))
+end
+
+!UNPARSE: SUBROUTINE f00 (x)
+!UNPARSE: INTEGER x(10_4)
+!UNPARSE: !$OMP METADIRECTIVE WHEN(USER={CONDITION(.true._4)}: ALLOCATE(x))
+!UNPARSE: END SUBROUTINE
+
+!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpMetadirectiveDirective
+!PARSE-TREE: | OmpClauseList -> OmpClause -> When -> OmpWhenClause
+!PARSE-TREE: | | Modifier -> OmpContextSelectorSpecification -> OmpTraitSetSelector
+!PARSE-TREE: | | | OmpTraitSetSelectorName -> Value = User
+!PARSE-TREE: | | | OmpTraitSelector
+!PARSE-TREE: | | | | OmpTraitSelectorName -> Value = Condition
+!PARSE-TREE: | | | | Properties
+!PARSE-TREE: | | | | | OmpTraitProperty -> Scalar -> Expr = '.true._4'
+!PARSE-TREE: | | | | | | LiteralConstant -> LogicalLiteralConstant
+!PARSE-TREE: | | | | | | | bool = 'true'
+!PARSE-TREE: | | OmpDirectiveSpecification
+!PARSE-TREE: | | | llvm::omp::Directive = allocate
+!PARSE-TREE: | | | OmpArgument -> OmpLocator -> OmpObject -> Designator -> DataRef -> Name = 'x'
+!PARSE-TREE: | | | OmpClauseList ->
+
+subroutine f01(x)
+ integer :: x
+ !$omp metadirective when(user={condition(.true.)}: &
+ !$omp & critical(x))
+end
+
+!UNPARSE: SUBROUTINE f01 (x)
+!UNPARSE: INTEGER x
+!UNPARSE: !$OMP METADIRECTIVE WHEN(USER={CONDITION(.true._4)}: CRITICAL(x))
+!UNPARSE: END SUBROUTINE
+
+!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpMetadirectiveDirective
+!PARSE-TREE: | OmpClauseList -> OmpClause -> When -> OmpWhenClause
+!PARSE-TREE: | | Modifier -> OmpContextSelectorSpecification -> OmpTraitSetSelector
+!PARSE-TREE: | | | OmpTraitSetSelectorName -> Value = User
+!PARSE-TREE: | | | OmpTraitSelector
+!PARSE-TREE: | | | | OmpTraitSelectorName -> Value = Condition
+!PARSE-TREE: | | | | Properties
+!PARSE-TREE: | | | | | OmpTraitProperty -> Scalar -> Expr = '.true._4'
+!PARSE-TREE: | | | | | | LiteralConstant -> LogicalLiteralConstant
+!PARSE-TREE: | | | | | | | bool = 'true'
+!PARSE-TREE: | | OmpDirectiveSpecification
+!PARSE-TREE: | | | llvm::omp::Directive = critical
+!PARSE-TREE: | | | OmpArgument -> OmpLocator -> OmpObject -> Designator -> DataRef -> Name = 'x'
+!PARSE-TREE: | | | OmpClauseList ->
+
+subroutine f02
+ !$omp metadirective when(user={condition(.true.)}: &
+ !$omp & declare mapper(mymapper : integer :: v) map(tofrom: v))
+end
+
+!UNPARSE: SUBROUTINE f02
+!UNPARSE: !$OMP METADIRECTIVE WHEN(USER={CONDITION(.true._4)}: DECLARE MAPPER(mymapper:INTEGER:&
+!UNPARSE: !$OMP&:v) MAP(TOFROM: v))
+!UNPARSE: END SUBROUTINE
+
+!PARSE-TREE: OpenMPDeclarativeConstruct -> OmpMetadirectiveDirective
+!PARSE-TREE: | OmpClauseList -> OmpClause -> When -> OmpWhenClause
+!PARSE-TREE: | | Modifier -> OmpContextSelectorSpecification -> OmpTraitSetSelector
+!PARSE-TREE: | | | OmpTraitSetSelectorName -> Value = User
+!PARSE-TREE: | | | OmpTraitSelector
+!PARSE-TREE: | | | | OmpTraitSelectorName -> Value = Condition
+!PARSE-TREE: | | | | Properties
+!PARSE-TREE: | | | | | OmpTraitProperty -> Scalar -> Expr = '.true._4'
+!PARSE-TREE: | | | | | | LiteralConstant -> LogicalLiteralConstant
+!PARSE-TREE: | | | | | | | bool = 'true'
+!PARSE-TREE: | | OmpDirectiveSpecification
+!PARSE-TREE: | | | llvm::omp::Directive = declare mapper
+!PARSE-TREE: | | | OmpArgument -> OmpMapperSpecifier
+!PARSE-TREE: | | | | Name = 'mymapper'
+!PARSE-TREE: | | | | TypeSpec -> IntrinsicTypeSpec -> IntegerTypeSpec ->
+!PARSE-TREE: | | | | Name = 'v'
+!PARSE-TREE: | | | OmpClauseList -> OmpClause -> Map -> OmpMapClause
+!PARSE-TREE: | | | | Modifier -> OmpMapType -> Value = Tofrom
+!PARSE-TREE: | | | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'v'
+!PARSE-TREE: | | | | bool = 'true'
+!PARSE-TREE: ImplicitPart ->
+
+subroutine f03
+ type :: tt1
+ integer :: x
+ endtype
+ type :: tt2
+ real :: a
+ endtype
+ !$omp metadirective when(user={condition(.true.)}: &
+ !$omp & declare reduction(+ : tt1, tt2 : omp_out = omp_in + omp_out))
+end
+
+!UNPARSE: SUBROUTINE f03
+!UNPARSE: TYPE :: tt1
+!UNPARSE: INTEGER :: x
+!UNPARSE: END TYPE
+!UNPARSE: TYPE :: tt2
+!UNPARSE: REAL :: a
+!UNPARSE: END TYPE
+!UNPARSE: !$OMP METADIRECTIVE WHEN(USER={CONDITION(.true._4)}: DECLARE REDUCTION(+:tt1,tt2: omp_out=omp_in+omp_out
+!UNPARSE: ))
+!UNPARSE: END SUBROUTINE
+
+!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpMetadirectiveDirective
+!PARSE-TREE: | OmpClauseList -> OmpClause -> When -> OmpWhenClause
+!PARSE-TREE: | | Modifier -> OmpContextSelectorSpecification -> OmpTraitSetSelector
+!PARSE-TREE: | | | OmpTraitSetSelectorName -> Value = User
+!PARSE-TREE: | | | OmpTraitSelector
+!PARSE-TREE: | | | | OmpTraitSelectorName -> Value = Condition
+!PARSE-TREE: | | | | Properties
+!PARSE-TREE: | | | | | OmpTraitProperty -> Scalar -> Expr = '.true._4'
+!PARSE-TREE: | | | | | | LiteralConstant -> LogicalLiteralConstant
+!PARSE-TREE: | | | | | | | bool = 'true'
+!PARSE-TREE: | | OmpDirectiveSpecification
+!PARSE-TREE: | | | llvm::omp::Directive = declare reduction
+!PARSE-TREE: | | | OmpArgument -> OmpReductionSpecifier
+!PARSE-TREE: | | | | OmpReductionIdentifier -> DefinedOperator -> IntrinsicOperator = Add
+!PARSE-TREE: | | | | OmpTypeNameList -> OmpTypeSpecifier -> TypeSpec -> DerivedTypeSpec
+!PARSE-TREE: | | | | | Name = 'tt1'
+!PARSE-TREE: | | | | OmpTypeSpecifier -> TypeSpec -> DerivedTypeSpec
+!PARSE-TREE: | | | | | Name = 'tt2'
+!PARSE-TREE: | | | | OmpReductionCombiner -> AssignmentStmt = 'omp_out=omp_in+omp_out'
+!PARSE-TREE: | | | | | Variable = 'omp_out'
+!PARSE-TREE: | | | | | | Designator -> DataRef -> Name = 'omp_out'
+!PARSE-TREE: | | | | | Expr = 'omp_in+omp_out'
+!PARSE-TREE: | | | | | | Add
+!PARSE-TREE: | | | | | | | Expr = 'omp_in'
+!PARSE-TREE: | | | | | | | | Designator -> DataRef -> Name = 'omp_in'
+!PARSE-TREE: | | | | | | | Expr = 'omp_out'
+!PARSE-TREE: | | | | | | | | Designator -> DataRef -> Name = 'omp_out'
+!PARSE-TREE: | | | OmpClauseList ->
+
+subroutine f04
+ !$omp metadirective when(user={condition(.true.)}: &
+ !$omp & declare simd(f04))
+end
+
+!UNPARSE: SUBROUTINE f04
+!UNPARSE: !$OMP METADIRECTIVE WHEN(USER={CONDITION(.true._4)}: DECLARE SIMD(f04))
+!UNPARSE: END SUBROUTINE
+
+!PARSE-TREE: OpenMPDeclarativeConstruct -> OmpMetadirectiveDirective
+!PARSE-TREE: | OmpClauseList -> OmpClause -> When -> OmpWhenClause
+!PARSE-TREE: | | Modifier -> OmpContextSelectorSpecification -> OmpTraitSetSelector
+!PARSE-TREE: | | | OmpTraitSetSelectorName -> Value = User
+!PARSE-TREE: | | | OmpTraitSelector
+!PARSE-TREE: | | | | OmpTraitSelectorName -> Value = Condition
+!PARSE-TREE: | | | | Properties
+!PARSE-TREE: | | | | | OmpTraitProperty -> Scalar -> Expr = '.true._4'
+!PARSE-TREE: | | | | | | LiteralConstant -> LogicalLiteralConstant
+!PARSE-TREE: | | | | | | | bool = 'true'
+!PARSE-TREE: | | OmpDirectiveSpecification
+!PARSE-TREE: | | | llvm::omp::Directive = declare simd
+!PARSE-TREE: | | | OmpArgument -> OmpLocator -> OmpObject -> Designator -> DataRef -> Name = 'f04'
+!PARSE-TREE: | | | OmpClauseList ->
+!PARSE-TREE: ImplicitPart ->
+
+subroutine f05
+ !$omp metadirective when(user={condition(.true.)}: &
+ !$omp & declare target(f05))
+end
+
+!UNPARSE: SUBROUTINE f05
+!UNPARSE: !$OMP METADIRECTIVE WHEN(USER={CONDITION(.true._4)}: DECLARE TARGET(f05))
+!UNPARSE: END SUBROUTINE
+
+!PARSE-TREE: OpenMPDeclarativeConstruct -> OmpMetadirectiveDirective
+!PARSE-TREE: | OmpClauseList -> OmpClause -> When -> OmpWhenClause
+!PARSE-TREE: | | Modifier -> OmpContextSelectorSpecification -> OmpTraitSetSelector
+!PARSE-TREE: | | | OmpTraitSetSelectorName -> Value = User
+!PARSE-TREE: | | | OmpTraitSelector
+!PARSE-TREE: | | | | OmpTraitSelectorName -> Value = Condition
+!PARSE-TREE: | | | | Properties
+!PARSE-TREE: | | | | | OmpTraitProperty -> Scalar -> Expr = '.true._4'
+!PARSE-TREE: | | | | | | LiteralConstant -> LogicalLiteralConstant
+!PARSE-TREE: | | | | | | | bool = 'true'
+!PARSE-TREE: | | OmpDirectiveSpecification
+!PARSE-TREE: | | | llvm::omp::Directive = declare target
+!PARSE-TREE: | | | OmpArgument -> OmpLocator -> OmpObject -> Designator -> DataRef -> Name = 'f05'
+!PARSE-TREE: | | | OmpClauseList ->
+!PARSE-TREE: ImplicitPart ->
+
+subroutine f06(x, y)
+ integer :: x, y
+ !$omp metadirective when(user={condition(.true.)}: &
+ !$omp & flush(x, y))
+end
+
+!UNPARSE: SUBROUTINE f06 (x, y)
+!UNPARSE: INTEGER x, y
+!UNPARSE: !$OMP METADIRECTIVE WHEN(USER={CONDITION(.true._4)}: FLUSH(x, y))
+!UNPARSE: END SUBROUTINE
+
+!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpMetadirectiveDirective
+!PARSE-TREE: | OmpClauseList -> OmpClause -> When -> OmpWhenClause
+!PARSE-TREE: | | Modifier -> OmpContextSelectorSpecification -> OmpTraitSetSelector
+!PARSE-TREE: | | | OmpTraitSetSelectorName -> Value = User
+!PARSE-TREE: | | | OmpTraitSelector
+!PARSE-TREE: | | | | OmpTraitSelectorName -> Value = Condition
+!PARSE-TREE: | | | | Properties
+!PARSE-TREE: | | | | | OmpTraitProperty -> Scalar -> Expr = '.true._4'
+!PARSE-TREE: | | | | | | LiteralConstant -> LogicalLiteralConstant
+!PARSE-TREE: | | | | | | | bool = 'true'
+!PARSE-TREE: | | OmpDirectiveSpecification
+!PARSE-TREE: | | | llvm::omp::Directive = flush
+!PARSE-TREE: | | | OmpArgument -> OmpLocator -> OmpObject -> Designator -> DataRef -> Name = 'x'
+!PARSE-TREE: | | | OmpArgument -> OmpLocator -> OmpObject -> Designator -> DataRef -> Name = 'y'
+!PARSE-TREE: | | | OmpClauseList ->
+
+subroutine f07
+ integer :: t
+ !$omp metadirective when(user={condition(.true.)}: &
+ !$omp & threadprivate(t))
+end
+
+!UNPARSE: SUBROUTINE f07
+!UNPARSE: INTEGER t
+!UNPARSE: !$OMP METADIRECTIVE WHEN(USER={CONDITION(.true._4)}: THREADPRIVATE(t))
+!UNPARSE: END SUBROUTINE
+
+!PARSE-TREE: DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OmpMetadirectiveDirective
+!PARSE-TREE: | OmpClauseList -> OmpClause -> When -> OmpWhenClause
+!PARSE-TREE: | | Modifier -> OmpContextSelectorSpecification -> OmpTraitSetSelector
+!PARSE-TREE: | | | OmpTraitSetSelectorName -> Value = User
+!PARSE-TREE: | | | OmpTraitSelector
+!PARSE-TREE: | | | | OmpTraitSelectorName -> Value = Condition
+!PARSE-TREE: | | | | Properties
+!PARSE-TREE: | | | | | OmpTraitProperty -> Scalar -> Expr = '.true._4'
+!PARSE-TREE: | | | | | | LiteralConstant -> LogicalLiteralConstant
+!PARSE-TREE: | | | | | | | bool = 'true'
+!PARSE-TREE: | | OmpDirectiveSpecification
+!PARSE-TREE: | | | llvm::omp::Directive = threadprivate
+!PARSE-TREE: | | | OmpArgument -> OmpLocator -> OmpObject -> Designator -> DataRef -> Name = 't'
+!PARSE-TREE: | | | OmpClauseList ->
More information about the llvm-branch-commits
mailing list