[flang-commits] [flang] [llvm] [flang][OpenMP] Rework LINEAR clause (PR #119278)
Krzysztof Parzyszek via flang-commits
flang-commits at lists.llvm.org
Mon Dec 9 14:19:32 PST 2024
https://github.com/kparzysz created https://github.com/llvm/llvm-project/pull/119278
The OmpLinearClause class was a variant of two classes, one for when the linear modifier was present, and one for when it was absent. These two classes did not follow the conventions for parse tree nodes, (i.e. tuple/wrapper/union formats), which necessitated specialization of the parse tree visitor.
The new form of OmpLinearClause is the standard tuple with a list of modifiers and an object list. The specialization of parse tree visitor for it has been removed.
Parsing and unparsing of the new form bears additional complexity due to syntactical differences between OpenMP 5.2 and prior versions: in OpenMP 5.2 the argument list is post-modified, while in the prior versions, the step modifier was a post-modifier while the linear modifier had an unusual syntax of `modifier(list)`.
With this change the LINEAR clause is no different from any other clauses in terms of its structure and use of modifiers. Modifier validation and all other checks work the same as with other clauses.
>From 919a6d74d15d1b3dff8577ef6a92ff79da1b042e Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Sat, 7 Dec 2024 14:16:22 -0600
Subject: [PATCH] [flang][OpenMP] Rework LINEAR clause
The OmpLinearClause class was a variant of two classes, one for when
the linear modifier was present, and one for when it was absent.
These two classes did not follow the conventions for parse tree nodes,
(i.e. tuple/wrapper/union formats), which necessitated specialization
of the parse tree visitor.
The new form of OmpLinearClause is the standard tuple with a list of
modifiers and an object list. The specialization of parse tree visitor
for it has been removed.
Parsing and unparsing of the new form bears additional complexity due
to syntactical differences between OpenMP 5.2 and prior versions: in
OpenMP 5.2 the argument list is post-modified, while in the prior
versions, the step modifier was a post-modifier while the linear
modifier had an unusual syntax of `modifier(list)`.
With this change the LINEAR clause is no different from any other
clauses in terms of its structure and use of modifiers. Modifier
validation and all other checks work the same as with other clauses.
---
flang/examples/FeatureList/FeatureList.cpp | 3 +-
flang/include/flang/Parser/dump-parse-tree.h | 5 +-
.../include/flang/Parser/parse-tree-visitor.h | 34 ----
flang/include/flang/Parser/parse-tree.h | 56 +++---
.../flang/Semantics/openmp-modifiers.h | 2 +
flang/lib/Lower/OpenMP/Clauses.cpp | 37 ++--
flang/lib/Parser/openmp-parsers.cpp | 64 +++++-
flang/lib/Parser/unparse.cpp | 62 +++++-
flang/lib/Semantics/check-omp-structure.cpp | 186 ++++++++----------
flang/lib/Semantics/openmp-modifiers.cpp | 33 ++++
flang/lib/Semantics/resolve-directives.cpp | 15 +-
flang/test/Parser/OpenMP/linear-clause.f90 | 117 +++++++++++
.../Semantics/OpenMP/clause-validity01.f90 | 8 +
.../test/Semantics/OpenMP/linear-clause01.f90 | 12 +-
.../test/Semantics/OpenMP/linear-clause02.f90 | 13 ++
flang/test/Semantics/OpenMP/linear-iter.f90 | 14 +-
llvm/include/llvm/Frontend/OpenMP/ClauseT.h | 6 +-
.../Frontend/OpenMPDecompositionTest.cpp | 15 +-
18 files changed, 449 insertions(+), 233 deletions(-)
create mode 100644 flang/test/Parser/OpenMP/linear-clause.f90
create mode 100644 flang/test/Semantics/OpenMP/linear-clause02.f90
diff --git a/flang/examples/FeatureList/FeatureList.cpp b/flang/examples/FeatureList/FeatureList.cpp
index 41a6255207976d..3a689c335c81c0 100644
--- a/flang/examples/FeatureList/FeatureList.cpp
+++ b/flang/examples/FeatureList/FeatureList.cpp
@@ -495,8 +495,7 @@ struct NodeVisitor {
READ_FEATURE(OmpIfClause::Modifier)
READ_FEATURE(OmpDirectiveNameModifier)
READ_FEATURE(OmpLinearClause)
- READ_FEATURE(OmpLinearClause::WithModifier)
- READ_FEATURE(OmpLinearClause::WithoutModifier)
+ READ_FEATURE(OmpLinearClause::Modifier)
READ_FEATURE(OmpLinearModifier)
READ_FEATURE(OmpLinearModifier::Value)
READ_FEATURE(OmpLoopDirective)
diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h
index c6f35a07d81ea5..e34777a6c64bba 100644
--- a/flang/include/flang/Parser/dump-parse-tree.h
+++ b/flang/include/flang/Parser/dump-parse-tree.h
@@ -558,10 +558,11 @@ class ParseTreeDumper {
NODE(parser, OmpLastprivateModifier)
NODE_ENUM(OmpLastprivateModifier, Value)
NODE(parser, OmpLinearClause)
- NODE(OmpLinearClause, WithModifier)
- NODE(OmpLinearClause, WithoutModifier)
+ NODE(OmpLinearClause, Modifier)
NODE(parser, OmpLinearModifier)
NODE_ENUM(OmpLinearModifier, Value)
+ NODE(parser, OmpStepComplexModifier)
+ NODE(parser, OmpStepSimpleModifier)
NODE(parser, OmpLoopDirective)
NODE(parser, OmpMapClause)
NODE(OmpMapClause, Modifier)
diff --git a/flang/include/flang/Parser/parse-tree-visitor.h b/flang/include/flang/Parser/parse-tree-visitor.h
index e1ea4d459f4a60..af1d34ae804f3c 100644
--- a/flang/include/flang/Parser/parse-tree-visitor.h
+++ b/flang/include/flang/Parser/parse-tree-visitor.h
@@ -897,40 +897,6 @@ struct ParseTreeVisitorLookupScope {
mutator.Post(x);
}
}
- template <typename V>
- static void Walk(const OmpLinearClause::WithModifier &x, V &visitor) {
- if (visitor.Pre(x)) {
- Walk(x.modifier, visitor);
- Walk(x.names, visitor);
- Walk(x.step, visitor);
- visitor.Post(x);
- }
- }
- template <typename M>
- static void Walk(OmpLinearClause::WithModifier &x, M &mutator) {
- if (mutator.Pre(x)) {
- Walk(x.modifier, mutator);
- Walk(x.names, mutator);
- Walk(x.step, mutator);
- mutator.Post(x);
- }
- }
- template <typename V>
- static void Walk(const OmpLinearClause::WithoutModifier &x, V &visitor) {
- if (visitor.Pre(x)) {
- Walk(x.names, visitor);
- Walk(x.step, visitor);
- visitor.Post(x);
- }
- }
- template <typename M>
- static void Walk(OmpLinearClause::WithoutModifier &x, M &mutator) {
- if (mutator.Pre(x)) {
- Walk(x.names, mutator);
- Walk(x.step, mutator);
- mutator.Post(x);
- }
- }
};
} // namespace detail
diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index 8160b095f06dd9..bd8db6b719d0a7 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -3698,6 +3698,22 @@ struct OmpReductionModifier {
WRAPPER_CLASS_BOILERPLATE(OmpReductionModifier, Value);
};
+// Ref: [5.2:117-120]
+//
+// step-complex-modifier ->
+// STEP(integer-expression) // since 5.2
+struct OmpStepComplexModifier {
+ WRAPPER_CLASS_BOILERPLATE(OmpStepComplexModifier, ScalarIntExpr);
+};
+
+// Ref: [4.5:207-210], [5.0:290-293], [5.1:323-325], [5.2:117-120]
+//
+// step-simple-modifier ->
+// integer-expresion // since 4.5
+struct OmpStepSimpleModifier {
+ WRAPPER_CLASS_BOILERPLATE(OmpStepSimpleModifier, ScalarIntExpr);
+};
+
// Ref: [4.5:169-170], [5.0:254-256], [5.1:287-289], [5.2:321]
//
// task-dependence-type -> // "dependence-type" in 5.1 and before
@@ -3925,7 +3941,7 @@ struct OmpDeviceTypeClause {
struct OmpFromClause {
TUPLE_CLASS_BOILERPLATE(OmpFromClause);
MODIFIER_BOILERPLATE(OmpExpectation, OmpIterator, OmpMapper);
- std::tuple<MODIFIERS(), OmpObjectList, bool> t;
+ std::tuple<MODIFIERS(), OmpObjectList, /*CommaSeparated=*/bool> t;
};
// Ref: [4.5:87-91], [5.0:140-146], [5.1:166-171], [5.2:269]
@@ -3969,28 +3985,20 @@ struct OmpLastprivateClause {
std::tuple<MODIFIERS(), OmpObjectList> t;
};
-// 2.15.3.7 linear-clause -> LINEAR (linear-list[ : linear-step])
-// linear-list -> list | linear-modifier(list)
+// Ref: [4.5:207-210], [5.0:290-293], [5.1:323-325], [5.2:117-120]
+//
+// linear-clause ->
+// LINEAR(list [: step-simple-modifier]) | // since 4.5
+// LINEAR(linear-modifier(list)
+// [: step-simple-modifier]) | // since 4.5, until 5.2[*]
+// LINEAR(list [: linear-modifier,
+// step-complex-modifier]) // since 5.2
+// [*] Still allowed in 5.2 when on DECLARE SIMD, but deprecated.
struct OmpLinearClause {
- UNION_CLASS_BOILERPLATE(OmpLinearClause);
- struct WithModifier {
- BOILERPLATE(WithModifier);
- WithModifier(OmpLinearModifier &&m, std::list<Name> &&n,
- std::optional<ScalarIntConstantExpr> &&s)
- : modifier(std::move(m)), names(std::move(n)), step(std::move(s)) {}
- OmpLinearModifier modifier;
- std::list<Name> names;
- std::optional<ScalarIntConstantExpr> step;
- };
- struct WithoutModifier {
- BOILERPLATE(WithoutModifier);
- WithoutModifier(
- std::list<Name> &&n, std::optional<ScalarIntConstantExpr> &&s)
- : names(std::move(n)), step(std::move(s)) {}
- std::list<Name> names;
- std::optional<ScalarIntConstantExpr> step;
- };
- std::variant<WithModifier, WithoutModifier> u;
+ TUPLE_CLASS_BOILERPLATE(OmpLinearClause);
+ MODIFIER_BOILERPLATE(
+ OmpLinearModifier, OmpStepSimpleModifier, OmpStepComplexModifier);
+ std::tuple<OmpObjectList, MODIFIERS(), /*PostModified=*/bool> t;
};
// Ref: [4.5:216-219], [5.0:315-324], [5.1:347-355], [5.2:150-158]
@@ -4005,7 +4013,7 @@ struct OmpLinearClause {
struct OmpMapClause {
TUPLE_CLASS_BOILERPLATE(OmpMapClause);
MODIFIER_BOILERPLATE(OmpMapTypeModifier, OmpMapper, OmpIterator, OmpMapType);
- std::tuple<MODIFIERS(), OmpObjectList, bool> t;
+ std::tuple<MODIFIERS(), OmpObjectList, /*CommaSeparated=*/bool> t;
};
// Ref: [4.5:87-91], [5.0:140-146], [5.1:166-171], [5.2:270]
@@ -4083,7 +4091,7 @@ struct OmpScheduleClause {
struct OmpToClause {
TUPLE_CLASS_BOILERPLATE(OmpToClause);
MODIFIER_BOILERPLATE(OmpExpectation, OmpIterator, OmpMapper);
- std::tuple<MODIFIERS(), OmpObjectList, bool> t;
+ std::tuple<MODIFIERS(), OmpObjectList, /*CommaSeparated=*/bool> t;
};
// Ref: [5.0:254-255], [5.1:287-288], [5.2:321-322]
diff --git a/flang/include/flang/Semantics/openmp-modifiers.h b/flang/include/flang/Semantics/openmp-modifiers.h
index 4025ce112d9cab..5d5c5e97faf413 100644
--- a/flang/include/flang/Semantics/openmp-modifiers.h
+++ b/flang/include/flang/Semantics/openmp-modifiers.h
@@ -87,6 +87,8 @@ DECLARE_DESCRIPTOR(parser::OmpOrderingModifier);
DECLARE_DESCRIPTOR(parser::OmpPrescriptiveness);
DECLARE_DESCRIPTOR(parser::OmpReductionIdentifier);
DECLARE_DESCRIPTOR(parser::OmpReductionModifier);
+DECLARE_DESCRIPTOR(parser::OmpStepComplexModifier);
+DECLARE_DESCRIPTOR(parser::OmpStepSimpleModifier);
DECLARE_DESCRIPTOR(parser::OmpTaskDependenceType);
DECLARE_DESCRIPTOR(parser::OmpVariableCategory);
diff --git a/flang/lib/Lower/OpenMP/Clauses.cpp b/flang/lib/Lower/OpenMP/Clauses.cpp
index 10c31963ec493a..8b1ddc7a7ccf28 100644
--- a/flang/lib/Lower/OpenMP/Clauses.cpp
+++ b/flang/lib/Lower/OpenMP/Clauses.cpp
@@ -895,8 +895,6 @@ Lastprivate make(const parser::OmpClause::Lastprivate &inp,
Linear make(const parser::OmpClause::Linear &inp,
semantics::SemanticsContext &semaCtx) {
// inp.v -> parser::OmpLinearClause
- using wrapped = parser::OmpLinearClause;
-
CLAUSET_ENUM_CONVERT( //
convert, parser::OmpLinearModifier::Value, Linear::LinearModifier,
// clang-format off
@@ -906,26 +904,23 @@ Linear make(const parser::OmpClause::Linear &inp,
// clang-format on
);
- using Tuple = decltype(Linear::t);
+ auto &mods = semantics::OmpGetModifiers(inp.v);
+ auto *m0 =
+ semantics::OmpGetUniqueModifier<parser::OmpStepComplexModifier>(mods);
+ auto *m1 =
+ semantics::OmpGetUniqueModifier<parser::OmpStepSimpleModifier>(mods);
+ assert((!m0 || !m1) && "Simple and complex modifiers both present");
- return Linear{Fortran::common::visit(
- common::visitors{
- [&](const wrapped::WithModifier &s) -> Tuple {
- return {
- /*StepSimpleModifier=*/std::nullopt,
- /*StepComplexModifier=*/maybeApply(makeExprFn(semaCtx), s.step),
- /*LinearModifier=*/convert(s.modifier.v),
- /*List=*/makeList(s.names, makeObjectFn(semaCtx))};
- },
- [&](const wrapped::WithoutModifier &s) -> Tuple {
- return {
- /*StepSimpleModifier=*/maybeApply(makeExprFn(semaCtx), s.step),
- /*StepComplexModifier=*/std::nullopt,
- /*LinearModifier=*/std::nullopt,
- /*List=*/makeList(s.names, makeObjectFn(semaCtx))};
- },
- },
- inp.v.u)};
+ auto *m2 = semantics::OmpGetUniqueModifier<parser::OmpLinearModifier>(mods);
+ auto &t1 = std::get<parser::OmpObjectList>(inp.v.t);
+
+ auto &&maybeStep = m0 ? maybeApplyToV(makeExprFn(semaCtx), m0)
+ : m1 ? maybeApplyToV(makeExprFn(semaCtx), m1)
+ : std::optional<Linear::StepComplexModifier>{};
+
+ return Linear{{/*StepComplexModifier=*/std::move(maybeStep),
+ /*LinearModifier=*/maybeApplyToV(convert, m2),
+ /*List=*/makeObjects(t1, semaCtx)}};
}
Link make(const parser::OmpClause::Link &inp,
diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp
index 86d475c1a15422..b7baa9759b0f55 100644
--- a/flang/lib/Parser/openmp-parsers.cpp
+++ b/flang/lib/Parser/openmp-parsers.cpp
@@ -99,6 +99,26 @@ constexpr ModifierList<Clause, Separator> modifierList(Separator sep) {
return ModifierList<Clause, Separator>(sep);
}
+// Parse the input as any modifier from ClauseTy, but only succeed if
+// the result was the SpecificTy. It requires that SpecificTy is one
+// of the alternatives in ClauseTy::Modifier.
+// The reason to have this is that ClauseTy::Modifier has "source",
+// while specific modifiers don't. This class allows to parse a specific
+// modifier together with obtaining its location.
+template <typename SpecificTy, typename ClauseTy>
+struct SpecificModifierParser {
+ using resultType = typename ClauseTy::Modifier;
+ std::optional<resultType> Parse(ParseState &state) const {
+ Parser<resultType> p;
+ if (auto result{attempt(Parser<resultType>{}).Parse(state)}) {
+ if (std::holds_alternative<SpecificTy>(result->u)) {
+ return result;
+ }
+ }
+ return std::nullopt;
+ }
+};
+
// OpenMP Clauses
// [5.0] 2.1.6 iterator-specifier -> type-declaration-stmt = subscript-triple |
@@ -232,6 +252,11 @@ TYPE_PARSER(construct<OmpReductionModifier>(
"TASK" >> pure(OmpReductionModifier::Value::Task) ||
"DEFAULT" >> pure(OmpReductionModifier::Value::Default)))
+TYPE_PARSER(construct<OmpStepComplexModifier>( //
+ "STEP" >> parenthesized(scalarIntExpr)))
+
+TYPE_PARSER(construct<OmpStepSimpleModifier>(scalarIntExpr))
+
TYPE_PARSER(construct<OmpTaskDependenceType>(
"DEPOBJ" >> pure(OmpTaskDependenceType::Value::Depobj) ||
"IN"_id >> pure(OmpTaskDependenceType::Value::In) ||
@@ -285,6 +310,11 @@ TYPE_PARSER(sourced(construct<OmpIfClause::Modifier>(OmpDirectiveNameParser{})))
TYPE_PARSER(sourced(construct<OmpLastprivateClause::Modifier>(
Parser<OmpLastprivateModifier>{})))
+TYPE_PARSER(sourced(
+ construct<OmpLinearClause::Modifier>(Parser<OmpLinearModifier>{}) ||
+ construct<OmpLinearClause::Modifier>(Parser<OmpStepComplexModifier>{}) ||
+ construct<OmpLinearClause::Modifier>(Parser<OmpStepSimpleModifier>{})))
+
TYPE_PARSER(sourced(construct<OmpMapClause::Modifier>(
sourced(construct<OmpMapClause::Modifier>(Parser<OmpMapTypeModifier>{}) ||
construct<OmpMapClause::Modifier>(Parser<OmpMapper>{}) ||
@@ -460,13 +490,33 @@ TYPE_PARSER(construct<OmpToClause>(
applyFunction<OmpToClause>(makeMobClause<false>,
modifierList<OmpToClause>(maybe(","_tok)), Parser<OmpObjectList>{})))
-TYPE_CONTEXT_PARSER("Omp LINEAR clause"_en_US,
- construct<OmpLinearClause>(
- construct<OmpLinearClause>(construct<OmpLinearClause::WithModifier>(
- Parser<OmpLinearModifier>{}, parenthesized(nonemptyList(name)),
- maybe(":" >> scalarIntConstantExpr))) ||
- construct<OmpLinearClause>(construct<OmpLinearClause::WithoutModifier>(
- nonemptyList(name), maybe(":" >> scalarIntConstantExpr)))))
+OmpLinearClause makeLinearFromOldSyntax(OmpLinearClause::Modifier &&lm,
+ OmpObjectList &&objs, std::optional<OmpLinearClause::Modifier> &&ssm) {
+ std::list<OmpLinearClause::Modifier> mods;
+ mods.emplace_back(std::move(lm));
+ if (ssm) {
+ mods.emplace_back(std::move(*ssm));
+ }
+ return OmpLinearClause{std::move(objs),
+ mods.empty() ? decltype(mods){} : std::move(mods),
+ /*PostModified=*/false};
+}
+
+TYPE_PARSER(
+ // Parse the "modifier(x)" first, because syntacticaly it will match
+ // an array element (i.e. a list item).
+ // LINEAR(linear-modifier(list) [: step-simple-modifier])
+ construct<OmpLinearClause>( //
+ applyFunction(makeLinearFromOldSyntax,
+ SpecificModifierParser<OmpLinearModifier, OmpLinearClause>{},
+ parenthesized(Parser<OmpObjectList>{}),
+ maybe(":"_tok >> SpecificModifierParser<OmpStepSimpleModifier,
+ OmpLinearClause>{}))) ||
+ // LINEAR(list [: modifiers])
+ construct<OmpLinearClause>( //
+ Parser<OmpObjectList>{},
+ maybe(":"_tok >> nonemptyList(Parser<OmpLinearClause::Modifier>{})),
+ /*PostModified=*/pure(true)))
// OpenMPv5.2 12.5.2 detach-clause -> DETACH (event-handle)
TYPE_PARSER(construct<OmpDetachClause>(Parser<OmpObject>{}))
diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp
index 4782cc1f2d7d7d..2085c62f74b8d7 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -2133,13 +2133,63 @@ class UnparseVisitor {
Walk(std::get<std::optional<std::list<Modifier>>>(x.t), ": ");
Walk(std::get<ScalarLogicalExpr>(x.t));
}
- void Unparse(const OmpLinearClause::WithoutModifier &x) {
- Walk(x.names, ", ");
- Walk(":", x.step);
+ void Unparse(const OmpStepSimpleModifier &x) { Walk(x.v); }
+ void Unparse(const OmpStepComplexModifier &x) {
+ Word("STEP(");
+ Walk(x.v);
+ Put(")");
}
- void Unparse(const OmpLinearClause::WithModifier &x) {
- Walk(x.modifier), Put("("), Walk(x.names, ","), Put(")");
- Walk(":", x.step);
+ void Unparse(const OmpLinearClause &x) {
+ using Modifier = OmpLinearClause::Modifier;
+ auto &modifiers{std::get<std::optional<std::list<Modifier>>>(x.t)};
+ if (std::get<bool>(x.t)) { // PostModified
+ Walk(std::get<OmpObjectList>(x.t));
+ Walk(": ", modifiers);
+ } else {
+ // Unparse using pre-5.2 syntax.
+ bool HasStepModifier{false}, HasLinearModifier{false};
+
+ if (modifiers) {
+ bool NeedComma{false};
+ for (const Modifier &m : *modifiers) {
+ // Print all linear modifiers in case we need to unparse an
+ // incorrect tree.
+ if (auto *lmod{std::get_if<parser::OmpLinearModifier>(&m.u)}) {
+ if (NeedComma) {
+ Put(",");
+ }
+ Walk(*lmod);
+ HasLinearModifier = true;
+ NeedComma = true;
+ } else {
+ // If not linear-modifier, then it has to be step modifier.
+ HasStepModifier = true;
+ }
+ }
+ }
+
+ if (HasLinearModifier) {
+ Put("(");
+ }
+ Walk(std::get<OmpObjectList>(x.t));
+ if (HasLinearModifier) {
+ Put(")");
+ }
+
+ if (HasStepModifier) {
+ Put(": ");
+ bool NeedComma{false};
+ for (const Modifier &m : *modifiers) {
+ if (!std::holds_alternative<parser::OmpLinearModifier>(m.u)) {
+ if (NeedComma) {
+ Put(",");
+ }
+ common::visit([&](auto &&s) { Walk(s); }, m.u);
+ NeedComma = true;
+ }
+ }
+ }
+ }
}
void Unparse(const OmpReductionClause &x) {
using Modifier = OmpReductionClause::Modifier;
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 3c9c5a02a338a6..e070466f64d452 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -414,14 +414,14 @@ void OmpStructureChecker::CheckMultListItems() {
// Linear clause
for (auto [_, clause] : FindClauses(llvm::omp::Clause::OMPC_linear)) {
- const auto &linearClause{std::get<parser::OmpClause::Linear>(clause->u)};
+ auto &linearClause{std::get<parser::OmpClause::Linear>(clause->u)};
std::list<parser::Name> nameList;
- common::visit(
- [&](const auto &u) {
- std::copy(
- u.names.begin(), u.names.end(), std::back_inserter(nameList));
- },
- linearClause.v.u);
+ SymbolSourceMap symbols;
+ GetSymbolsInObjectList(
+ std::get<parser::OmpObjectList>(linearClause.v.t), symbols);
+ llvm::transform(symbols, std::back_inserter(nameList), [&](auto &&pair) {
+ return parser::Name{pair.second, const_cast<Symbol *>(pair.first)};
+ });
CheckMultipleOccurrence(listVars, nameList, clause->source, "LINEAR");
}
}
@@ -958,28 +958,13 @@ void OmpStructureChecker::CheckDistLinear(
const auto &beginLoopDir{std::get<parser::OmpBeginLoopDirective>(x.t)};
const auto &clauses{std::get<parser::OmpClauseList>(beginLoopDir.t)};
- semantics::UnorderedSymbolSet indexVars;
+ SymbolSourceMap indexVars;
// Collect symbols of all the variables from linear clauses
- for (const auto &clause : clauses.v) {
- if (const auto *linearClause{
- std::get_if<parser::OmpClause::Linear>(&clause.u)}) {
-
- std::list<parser::Name> values;
- // Get the variant type
- if (std::holds_alternative<parser::OmpLinearClause::WithModifier>(
- linearClause->v.u)) {
- const auto &withM{
- std::get<parser::OmpLinearClause::WithModifier>(linearClause->v.u)};
- values = withM.names;
- } else {
- const auto &withOutM{std::get<parser::OmpLinearClause::WithoutModifier>(
- linearClause->v.u)};
- values = withOutM.names;
- }
- for (auto const &v : values) {
- indexVars.insert(*(v.symbol));
- }
+ for (auto &clause : clauses.v) {
+ if (auto *linearClause{std::get_if<parser::OmpClause::Linear>(&clause.u)}) {
+ auto &objects{std::get<parser::OmpObjectList>(linearClause->v.t)};
+ GetSymbolsInObjectList(objects, indexVars);
}
}
@@ -999,8 +984,8 @@ void OmpStructureChecker::CheckDistLinear(
if (loop->IsDoNormal()) {
const parser::Name &itrVal{GetLoopIndex(loop)};
if (itrVal.symbol) {
- // Remove the symbol from the collcted set
- indexVars.erase(*(itrVal.symbol));
+ // Remove the symbol from the collected set
+ indexVars.erase(&itrVal.symbol->GetUltimate());
}
collapseVal--;
if (collapseVal == 0) {
@@ -1016,12 +1001,10 @@ void OmpStructureChecker::CheckDistLinear(
}
// Show error for the remaining variables
- for (auto var : indexVars) {
- const Symbol &root{GetAssociationRoot(var)};
- context_.Say(parser::FindSourceLocation(x),
- "Variable '%s' not allowed in `LINEAR` clause, only loop iterator "
- "can be specified in `LINEAR` clause of a construct combined with "
- "`DISTRIBUTE`"_err_en_US,
+ for (auto &[symbol, source] : indexVars) {
+ const Symbol &root{GetAssociationRoot(*symbol)};
+ context_.Say(source,
+ "Variable '%s' not allowed in LINEAR clause, only loop iterator can be specified in LINEAR clause of a construct combined with DISTRIBUTE"_err_en_US,
root.name());
}
}
@@ -3619,17 +3602,63 @@ void OmpStructureChecker::Enter(const parser::OmpClause::If &x) {
void OmpStructureChecker::Enter(const parser::OmpClause::Linear &x) {
CheckAllowedClause(llvm::omp::Clause::OMPC_linear);
+ unsigned version{context_.langOptions().OpenMPVersion};
+ llvm::omp::Directive dir{GetContext().directive};
+ parser::CharBlock clauseSource{GetContext().clauseSource};
+ const parser::OmpLinearModifier *linearMod{nullptr};
- parser::CharBlock source{GetContext().clauseSource};
- // 2.7 Loop Construct Restriction
- if ((llvm::omp::allDoSet | llvm::omp::allSimdSet)
- .test(GetContext().directive)) {
- if (std::holds_alternative<parser::OmpLinearClause::WithModifier>(x.v.u)) {
+ SymbolSourceMap symbols;
+ auto &objects{std::get<parser::OmpObjectList>(x.v.t)};
+ GetSymbolsInObjectList(objects, symbols);
+
+ auto CheckIntegerNoRef{[&](const Symbol *symbol, parser::CharBlock source) {
+ if (!symbol->GetType()->IsNumeric(TypeCategory::Integer)) {
+ auto &desc{OmpGetDescriptor<parser::OmpLinearModifier>()};
context_.Say(source,
- "A modifier may not be specified in a LINEAR clause "
- "on the %s directive"_err_en_US,
- ContextDirectiveAsFortran());
- return;
+ "The list item '%s' specified without the REF '%s' must be of INTEGER type"_err_en_US,
+ symbol->name(), desc.name.str());
+ }
+ }};
+
+ if (OmpVerifyModifiers(x.v, llvm::omp::OMPC_linear, clauseSource, context_)) {
+ auto &modifiers{OmpGetModifiers(x.v)};
+ linearMod = OmpGetUniqueModifier<parser::OmpLinearModifier>(modifiers);
+ if (linearMod) {
+ // 2.7 Loop Construct Restriction
+ if ((llvm::omp::allDoSet | llvm::omp::allSimdSet).test(dir)) {
+ context_.Say(clauseSource,
+ "A modifier may not be specified in a LINEAR clause on the %s directive"_err_en_US,
+ ContextDirectiveAsFortran());
+ return;
+ }
+
+ auto &desc{OmpGetDescriptor<parser::OmpLinearModifier>()};
+ for (auto &[symbol, source] : symbols) {
+ if (linearMod->v != parser::OmpLinearModifier::Value::Ref) {
+ CheckIntegerNoRef(symbol, source);
+ } else {
+ if (!IsAllocatable(*symbol) && !IsAssumedShape(*symbol) &&
+ !IsPolymorphic(*symbol)) {
+ context_.Say(source,
+ "The list item `%s` specified with the REF '%s' must be polymorphic variable, assumed-shape array, or a variable with the `ALLOCATABLE` attribute"_err_en_US,
+ symbol->name(), desc.name.str());
+ }
+ }
+ if (linearMod->v == parser::OmpLinearModifier::Value::Ref ||
+ linearMod->v == parser::OmpLinearModifier::Value::Uval) {
+ if (!IsDummy(*symbol) || IsValue(*symbol)) {
+ context_.Say(source,
+ "If the `%s` is REF or UVAL, the list item '%s' must be a dummy argument without the VALUE attribute"_err_en_US,
+ desc.name.str(), symbol->name());
+ }
+ }
+ } // for (symbol, source)
+
+ if (version >= 52 && !std::get</*PostModified=*/bool>(x.v.t)) {
+ context_.Say(OmpGetModifierSource(modifiers, linearMod),
+ "The 'modifier(<list>)' syntax is deprecated in %s, use '<list> : modifier' instead"_warn_en_US,
+ ThisVersion(version));
+ }
}
}
@@ -3642,73 +3671,28 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Linear &x) {
}
}
- auto checkForValidLinearClause_01 = [&](const parser::Name &name,
- bool is_ref) {
- std::string listItemName{name.ToString()};
- if (!is_ref && !name.symbol->GetType()->IsNumeric(TypeCategory::Integer)) {
- context_.Say(source,
- "The list item `%s` specified with other than linear-modifier `REF` must be of type INTEGER"_err_en_US,
- listItemName);
+ // OpenMP 5.2: Linear clause Restrictions
+ for (auto &[symbol, source] : symbols) {
+ if (!linearMod) {
+ // Already checked this with the modifier present.
+ CheckIntegerNoRef(symbol, source);
}
- if (GetContext().directive == llvm::omp::Directive::OMPD_declare_simd &&
- !IsDummy(*name.symbol)) {
+ if (dir == llvm::omp::Directive::OMPD_declare_simd && !IsDummy(*symbol)) {
context_.Say(source,
"The list item `%s` must be a dummy argument"_err_en_US,
- listItemName);
+ symbol->name());
}
- if (IsPointer(*name.symbol) ||
- name.symbol->test(Symbol::Flag::CrayPointer)) {
+ if (IsPointer(*symbol) || symbol->test(Symbol::Flag::CrayPointer)) {
context_.Say(source,
"The list item `%s` in a LINEAR clause must not be Cray Pointer or a variable with POINTER attribute"_err_en_US,
- listItemName);
+ symbol->name());
}
- if (FindCommonBlockContaining(*name.symbol)) {
+ if (FindCommonBlockContaining(*symbol)) {
context_.Say(source,
"'%s' is a common block name and must not appear in an LINEAR clause"_err_en_US,
- listItemName);
- }
- };
-
- auto checkForValidLinearClause_02 = [&](const parser::Name &name,
- const parser::OmpLinearModifier::Value
- &modifierValue) {
- std::string listItemName{name.ToString()};
- checkForValidLinearClause_01(
- name, (modifierValue == parser::OmpLinearModifier::Value::Ref));
- if (modifierValue != parser::OmpLinearModifier::Value::Val &&
- IsDummy(*name.symbol) && IsValue(*name.symbol)) {
- context_.Say(source,
- "The list item `%s` specified with the linear-modifier `REF` or `UVAL` must be a dummy argument without `VALUE` attribute"_err_en_US,
- listItemName);
- }
- if (modifierValue == parser::OmpLinearModifier::Value::Ref &&
- !(IsAllocatable(*name.symbol) || IsAssumedShape(*name.symbol) ||
- IsPolymorphic(*name.symbol))) {
- context_.Say(source,
- "The list item `%s` specified with the linear-modifier `REF` must be polymorphic variable, assumed-shape array, or a variable with the `ALLOCATABLE` attribute"_err_en_US,
- listItemName);
+ symbol->name());
}
- };
-
- // OpenMP 5.2: Linear clause Restrictions
- common::visit(
- common::visitors{
- [&](const parser::OmpLinearClause::WithoutModifier &withoutModifier) {
- for (const auto &name : withoutModifier.names) {
- if (name.symbol) {
- checkForValidLinearClause_01(name, false);
- }
- }
- },
- [&](const parser::OmpLinearClause::WithModifier &withModifier) {
- for (const auto &name : withModifier.names) {
- if (name.symbol) {
- checkForValidLinearClause_02(name, withModifier.modifier.v);
- }
- }
- },
- },
- x.v.u);
+ }
}
void OmpStructureChecker::CheckAllowedMapTypes(
diff --git a/flang/lib/Semantics/openmp-modifiers.cpp b/flang/lib/Semantics/openmp-modifiers.cpp
index f8f81e6c6ffa15..9f2896229bb7ff 100644
--- a/flang/lib/Semantics/openmp-modifiers.cpp
+++ b/flang/lib/Semantics/openmp-modifiers.cpp
@@ -407,6 +407,39 @@ const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpReductionModifier>() {
return desc;
}
+template <>
+const OmpModifierDescriptor &
+OmpGetDescriptor<parser::OmpStepComplexModifier>() {
+ static const OmpModifierDescriptor desc{
+ /*name=*/"step-complex-modifier",
+ /*props=*/
+ {
+ {52, {OmpProperty::Unique}},
+ },
+ /*clauses=*/
+ {
+ {52, {Clause::OMPC_linear}},
+ },
+ };
+ return desc;
+}
+
+template <>
+const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpStepSimpleModifier>() {
+ static const OmpModifierDescriptor desc{
+ /*name=*/"step-simple-modifier",
+ /*props=*/
+ {
+ {45, {OmpProperty::Unique, OmpProperty::Exclusive}},
+ },
+ /*clauses=*/
+ {
+ {45, {Clause::OMPC_linear}},
+ },
+ };
+ return desc;
+}
+
template <>
const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpTaskDependenceType>() {
static const OmpModifierDescriptor desc{
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index 80a086acebba20..39478b58a9070d 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -502,19 +502,8 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
return false;
}
bool Pre(const parser::OmpLinearClause &x) {
- common::visit(common::visitors{
- [&](const parser::OmpLinearClause::WithoutModifier
- &linearWithoutModifier) {
- ResolveOmpNameList(linearWithoutModifier.names,
- Symbol::Flag::OmpLinear);
- },
- [&](const parser::OmpLinearClause::WithModifier
- &linearWithModifier) {
- ResolveOmpNameList(
- linearWithModifier.names, Symbol::Flag::OmpLinear);
- },
- },
- x.u);
+ auto &objects{std::get<parser::OmpObjectList>(x.t)};
+ ResolveOmpObjectList(objects, Symbol::Flag::OmpLinear);
return false;
}
diff --git a/flang/test/Parser/OpenMP/linear-clause.f90 b/flang/test/Parser/OpenMP/linear-clause.f90
new file mode 100644
index 00000000000000..5f031b06941492
--- /dev/null
+++ b/flang/test/Parser/OpenMP/linear-clause.f90
@@ -0,0 +1,117 @@
+!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
+
+subroutine f00(x)
+ integer :: x
+ !$omp do linear(x)
+ do x = 1, 10
+ enddo
+ !$omp end do
+end
+
+!UNPARSE: SUBROUTINE f00 (x)
+!UNPARSE: INTEGER x
+!UNPARSE: !$OMP DO LINEAR(x)
+!UNPARSE: DO x=1_4,10_4
+!UNPARSE: END DO
+!UNPARSE: !$OMP END DO
+!UNPARSE: END SUBROUTINE
+
+!PARSE-TREE: OmpBeginLoopDirective
+!PARSE-TREE: | OmpLoopDirective -> llvm::omp::Directive = do
+!PARSE-TREE: | OmpClauseList -> OmpClause -> Linear -> OmpLinearClause
+!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
+!PARSE-TREE: | | bool = 'true'
+!PARSE-TREE: DoConstruct
+
+subroutine f01(x)
+ integer :: x
+ !$omp do linear(x : 2)
+ do x = 1, 10
+ enddo
+ !$omp end do
+end
+
+!UNPARSE: SUBROUTINE f01 (x)
+!UNPARSE: INTEGER x
+!UNPARSE: !$OMP DO LINEAR(x: 2_4)
+!UNPARSE: DO x=1_4,10_4
+!UNPARSE: END DO
+!UNPARSE: !$OMP END DO
+!UNPARSE: END SUBROUTINE
+
+!PARSE-TREE: OmpBeginLoopDirective
+!PARSE-TREE: | OmpLoopDirective -> llvm::omp::Directive = do
+!PARSE-TREE: | OmpClauseList -> OmpClause -> Linear -> OmpLinearClause
+!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
+!PARSE-TREE: | | Modifier -> OmpStepSimpleModifier -> Scalar -> Integer -> Expr = '2_4'
+!PARSE-TREE: | | | LiteralConstant -> IntLiteralConstant = '2'
+!PARSE-TREE: | | bool = 'true'
+!PARSE-TREE: DoConstruct
+
+subroutine f02(x)
+ integer :: x
+ !$omp do linear(x : step(3))
+ do x = 1, 10
+ enddo
+ !$omp end do
+end
+
+!UNPARSE: SUBROUTINE f02 (x)
+!UNPARSE: INTEGER x
+!UNPARSE: !$OMP DO LINEAR(x: STEP(3_4))
+!UNPARSE: DO x=1_4,10_4
+!UNPARSE: END DO
+!UNPARSE: !$OMP END DO
+!UNPARSE: END SUBROUTINE
+
+!PARSE-TREE: OmpBeginLoopDirective
+!PARSE-TREE: | OmpLoopDirective -> llvm::omp::Directive = do
+!PARSE-TREE: | OmpClauseList -> OmpClause -> Linear -> OmpLinearClause
+!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
+!PARSE-TREE: | | Modifier -> OmpStepComplexModifier -> Scalar -> Integer -> Expr = '3_4'
+!PARSE-TREE: | | | LiteralConstant -> IntLiteralConstant = '3'
+!PARSE-TREE: | | bool = 'true'
+!PARSE-TREE: DoConstruct
+
+subroutine f03(x)
+ integer :: x
+ !$omp declare simd linear(x : uval)
+end
+
+!UNPARSE: SUBROUTINE f03 (x)
+!UNPARSE: INTEGER x
+!UNPARSE: !$OMP DECLARE SIMD LINEAR(x: UVAL)
+!UNPARSE: END SUBROUTINE
+
+!PARSE-TREE: SpecificationPart
+![...]
+!PARSE-TREE: | DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareSimdConstruct
+!PARSE-TREE: | | Verbatim
+!PARSE-TREE: | | OmpClauseList -> OmpClause -> Linear -> OmpLinearClause
+!PARSE-TREE: | | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
+!PARSE-TREE: | | | Modifier -> OmpLinearModifier -> Value = Uval
+!PARSE-TREE: | | | bool = 'true'
+!PARSE-TREE: ExecutionPart -> Block
+
+subroutine f04(x)
+ integer :: x
+ !$omp declare simd linear(x : uval, step(3))
+end
+
+!UNPARSE: SUBROUTINE f04 (x)
+!UNPARSE: INTEGER x
+!UNPARSE: !$OMP DECLARE SIMD LINEAR(x: UVAL, STEP(3_4))
+!UNPARSE: END SUBROUTINE
+
+!PARSE-TREE: SpecificationPart
+![...]
+!PARSE-TREE: | DeclarationConstruct -> SpecificationConstruct -> OpenMPDeclarativeConstruct -> OpenMPDeclareSimdConstruct
+!PARSE-TREE: | | Verbatim
+!PARSE-TREE: | | OmpClauseList -> OmpClause -> Linear -> OmpLinearClause
+!PARSE-TREE: | | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
+!PARSE-TREE: | | | Modifier -> OmpLinearModifier -> Value = Uval
+!PARSE-TREE: | | | Modifier -> OmpStepComplexModifier -> Scalar -> Integer -> Expr = '3_4'
+!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '3'
+!PARSE-TREE: | | | bool = 'true'
+!PARSE-TREE: ExecutionPart -> Block
diff --git a/flang/test/Semantics/OpenMP/clause-validity01.f90 b/flang/test/Semantics/OpenMP/clause-validity01.f90
index 66e11e4b540f0f..e8114154a809bf 100644
--- a/flang/test/Semantics/OpenMP/clause-validity01.f90
+++ b/flang/test/Semantics/OpenMP/clause-validity01.f90
@@ -221,11 +221,19 @@
!ERROR: Clause LINEAR is not allowed if clause ORDERED appears on the DO directive
!ERROR: The parameter of the ORDERED clause must be a constant positive integer expression
+ !ERROR: 'b' appears in more than one data-sharing clause on the same OpenMP directive
!$omp do ordered(1-1) private(b) linear(b) linear(a)
do i = 1, N
a = 3.14
enddo
+ !ERROR: Clause LINEAR is not allowed if clause ORDERED appears on the DO directive
+ !ERROR: The parameter of the ORDERED clause must be a constant positive integer expression
+ !$omp do ordered(1-1) linear(a)
+ do i = 1, N
+ a = 3.14
+ enddo
+
!ERROR: The parameter of the ORDERED clause must be greater than or equal to the parameter of the COLLAPSE clause
!$omp do collapse(num-14) ordered(1)
do i = 1, N
diff --git a/flang/test/Semantics/OpenMP/linear-clause01.f90 b/flang/test/Semantics/OpenMP/linear-clause01.f90
index 654aa07f5bd403..f95e834c9026cb 100644
--- a/flang/test/Semantics/OpenMP/linear-clause01.f90
+++ b/flang/test/Semantics/OpenMP/linear-clause01.f90
@@ -16,25 +16,31 @@ end subroutine linear_clause_01
! Case 2
subroutine linear_clause_02(arg_01, arg_02)
- !ERROR: The list item `arg_01` specified with other than linear-modifier `REF` must be of type INTEGER
+ !ERROR: The list item 'arg_01' specified without the REF 'linear-modifier' must be of INTEGER type
!$omp declare simd linear(val(arg_01))
real, intent(in) :: arg_01(:)
- !ERROR: The list item `arg_02` specified with the linear-modifier `REF` or `UVAL` must be a dummy argument without `VALUE` attribute
+ !ERROR: The list item 'arg_02' specified without the REF 'linear-modifier' must be of INTEGER type
+ !ERROR: If the `linear-modifier` is REF or UVAL, the list item 'arg_02' must be a dummy argument without the VALUE attribute
!$omp declare simd linear(uval(arg_02))
+ !ERROR: The type of 'arg_02' has already been implicitly declared
integer, value, intent(in) :: arg_02
+ !ERROR: The list item 'var' specified without the REF 'linear-modifier' must be of INTEGER type
+ !ERROR: If the `linear-modifier` is REF or UVAL, the list item 'var' must be a dummy argument without the VALUE attribute
!ERROR: The list item `var` must be a dummy argument
!ERROR: The list item `var` in a LINEAR clause must not be Cray Pointer or a variable with POINTER attribute
!$omp declare simd linear(uval(var))
+ !ERROR: The type of 'var' has already been implicitly declared
integer, pointer :: var
end subroutine linear_clause_02
! Case 3
subroutine linear_clause_03(arg)
integer, intent(in) :: arg
- !ERROR: The list item `arg` specified with the linear-modifier `REF` must be polymorphic variable, assumed-shape array, or a variable with the `ALLOCATABLE` attribute
+ !ERROR: The list item `arg` specified with the REF 'linear-modifier' must be polymorphic variable, assumed-shape array, or a variable with the `ALLOCATABLE` attribute
!ERROR: List item 'arg' present at multiple LINEAR clauses
+ !ERROR: 'arg' appears in more than one data-sharing clause on the same OpenMP directive
!$omp declare simd linear(ref(arg)) linear(arg)
integer :: i
diff --git a/flang/test/Semantics/OpenMP/linear-clause02.f90 b/flang/test/Semantics/OpenMP/linear-clause02.f90
new file mode 100644
index 00000000000000..695d61715820f4
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/linear-clause02.f90
@@ -0,0 +1,13 @@
+!RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=52
+
+subroutine f00(x)
+ integer :: x
+ !WARNING: The 'modifier(<list>)' syntax is deprecated in OpenMP v5.2, use '<list> : modifier' instead
+ !$omp declare simd linear(uval(x))
+end
+
+subroutine f01(x)
+ integer :: x
+ !ERROR: An exclusive 'step-simple-modifier' modifier cannot be specified together with a modifier of a different type
+ !$omp declare simd linear(uval(x) : 2)
+end
diff --git a/flang/test/Semantics/OpenMP/linear-iter.f90 b/flang/test/Semantics/OpenMP/linear-iter.f90
index 8102c1a03cd37d..1f40228be92ad0 100644
--- a/flang/test/Semantics/OpenMP/linear-iter.f90
+++ b/flang/test/Semantics/OpenMP/linear-iter.f90
@@ -20,7 +20,7 @@ SUBROUTINE LINEAR_BAD(N)
!$omp target
!$omp teams
- !ERROR: Variable 'j' not allowed in `LINEAR` clause, only loop iterator can be specified in `LINEAR` clause of a construct combined with `DISTRIBUTE`
+ !ERROR: Variable 'j' not allowed in LINEAR clause, only loop iterator can be specified in LINEAR clause of a construct combined with DISTRIBUTE
!$omp distribute parallel do simd linear(j)
do i = 1, N
a = 3.14
@@ -31,8 +31,8 @@ SUBROUTINE LINEAR_BAD(N)
!$omp target
!$omp teams
- !ERROR: Variable 'j' not allowed in `LINEAR` clause, only loop iterator can be specified in `LINEAR` clause of a construct combined with `DISTRIBUTE`
- !ERROR: Variable 'b' not allowed in `LINEAR` clause, only loop iterator can be specified in `LINEAR` clause of a construct combined with `DISTRIBUTE`
+ !ERROR: Variable 'j' not allowed in LINEAR clause, only loop iterator can be specified in LINEAR clause of a construct combined with DISTRIBUTE
+ !ERROR: Variable 'b' not allowed in LINEAR clause, only loop iterator can be specified in LINEAR clause of a construct combined with DISTRIBUTE
!$omp distribute parallel do simd linear(j) linear(b)
do i = 1, N
a = 3.14
@@ -43,8 +43,8 @@ SUBROUTINE LINEAR_BAD(N)
!$omp target
!$omp teams
- !ERROR: Variable 'j' not allowed in `LINEAR` clause, only loop iterator can be specified in `LINEAR` clause of a construct combined with `DISTRIBUTE`
- !ERROR: Variable 'b' not allowed in `LINEAR` clause, only loop iterator can be specified in `LINEAR` clause of a construct combined with `DISTRIBUTE`
+ !ERROR: Variable 'j' not allowed in LINEAR clause, only loop iterator can be specified in LINEAR clause of a construct combined with DISTRIBUTE
+ !ERROR: Variable 'b' not allowed in LINEAR clause, only loop iterator can be specified in LINEAR clause of a construct combined with DISTRIBUTE
!$omp distribute parallel do simd linear(j, b)
do i = 1, N
a = 3.14
@@ -54,7 +54,7 @@ SUBROUTINE LINEAR_BAD(N)
!$omp end target
!ERROR: `DISTRIBUTE` region has to be strictly nested inside `TEAMS` region.
- !ERROR: Variable 'j' not allowed in `LINEAR` clause, only loop iterator can be specified in `LINEAR` clause of a construct combined with `DISTRIBUTE`
+ !ERROR: Variable 'j' not allowed in LINEAR clause, only loop iterator can be specified in LINEAR clause of a construct combined with DISTRIBUTE
!$omp distribute simd linear(i,j)
do i = 1, N
do j = 1, N
@@ -64,7 +64,7 @@ SUBROUTINE LINEAR_BAD(N)
!$omp end distribute simd
!ERROR: `DISTRIBUTE` region has to be strictly nested inside `TEAMS` region.
- !ERROR: Variable 'j' not allowed in `LINEAR` clause, only loop iterator can be specified in `LINEAR` clause of a construct combined with `DISTRIBUTE`
+ !ERROR: Variable 'j' not allowed in LINEAR clause, only loop iterator can be specified in LINEAR clause of a construct combined with DISTRIBUTE
!$omp distribute simd linear(i,j) collapse(1)
do i = 1, N
do j = 1, N
diff --git a/llvm/include/llvm/Frontend/OpenMP/ClauseT.h b/llvm/include/llvm/Frontend/OpenMP/ClauseT.h
index 67632fb79f8aac..3e22b6ff71c8f0 100644
--- a/llvm/include/llvm/Frontend/OpenMP/ClauseT.h
+++ b/llvm/include/llvm/Frontend/OpenMP/ClauseT.h
@@ -758,15 +758,13 @@ template <typename T, typename I, typename E> //
struct LinearT {
// std::get<type> won't work here due to duplicate types in the tuple.
using List = ObjectListT<I, E>;
- using StepSimpleModifier = E;
+ // StepSimpleModifier is same as StepComplexModifier.
using StepComplexModifier = E;
ENUM(LinearModifier, Ref, Val, Uval);
using TupleTrait = std::true_type;
// Step == nullopt means 1.
- std::tuple<OPT(StepSimpleModifier), OPT(StepComplexModifier),
- OPT(LinearModifier), List>
- t;
+ std::tuple<OPT(StepComplexModifier), OPT(LinearModifier), List> t;
};
// V5.2: [5.8.5] `link` clause
diff --git a/llvm/unittests/Frontend/OpenMPDecompositionTest.cpp b/llvm/unittests/Frontend/OpenMPDecompositionTest.cpp
index 8f195c4f603268..d218de225c3629 100644
--- a/llvm/unittests/Frontend/OpenMPDecompositionTest.cpp
+++ b/llvm/unittests/Frontend/OpenMPDecompositionTest.cpp
@@ -748,8 +748,7 @@ TEST_F(OpenMPDecompositionTest, Allocate3) {
// Allocate + linear
omp::List<omp::Clause> Clauses{
{OMPC_allocate, omp::clause::Allocate{{std::nullopt, std::nullopt, {x}}}},
- {OMPC_linear,
- omp::clause::Linear{{std::nullopt, std::nullopt, std::nullopt, {x}}}},
+ {OMPC_linear, omp::clause::Linear{{std::nullopt, std::nullopt, {x}}}},
};
omp::ConstructDecomposition Dec(AnyVersion, Helper, OMPD_parallel_for,
@@ -761,7 +760,7 @@ TEST_F(OpenMPDecompositionTest, Allocate3) {
// The "shared" clause is duplicated---this isn't harmful, but it
// should be fixed eventually.
ASSERT_EQ(Dir0, "parallel shared(x) shared(x)"); // (33)
- ASSERT_EQ(Dir1, "for linear(, , , (x)) firstprivate(x) lastprivate(, (x)) "
+ ASSERT_EQ(Dir1, "for linear(, , (x)) firstprivate(x) lastprivate(, (x)) "
"allocate(, , (x))"); // (33)
}
@@ -1059,8 +1058,7 @@ TEST_F(OpenMPDecompositionTest, Linear1) {
omp::Object x{"x"};
omp::List<omp::Clause> Clauses{
- {OMPC_linear,
- omp::clause::Linear{{std::nullopt, std::nullopt, std::nullopt, {x}}}},
+ {OMPC_linear, omp::clause::Linear{{std::nullopt, std::nullopt, {x}}}},
};
omp::ConstructDecomposition Dec(AnyVersion, Helper, OMPD_for_simd, Clauses);
@@ -1068,7 +1066,7 @@ TEST_F(OpenMPDecompositionTest, Linear1) {
std::string Dir0 = stringify(Dec.output[0]);
std::string Dir1 = stringify(Dec.output[1]);
ASSERT_EQ(Dir0, "for firstprivate(x) lastprivate(, (x))"); // (15.1), (15.2)
- ASSERT_EQ(Dir1, "simd linear(, , , (x)) lastprivate(, (x))"); // (15.1)
+ ASSERT_EQ(Dir1, "simd linear(, , (x)) lastprivate(, (x))"); // (15.1)
}
// NOWAIT
@@ -1102,13 +1100,12 @@ TEST_F(OpenMPDecompositionTest, Nowait1) {
TEST_F(OpenMPDecompositionTest, Misc1) {
omp::Object x{"x"};
omp::List<omp::Clause> Clauses{
- {OMPC_linear,
- omp::clause::Linear{{std::nullopt, std::nullopt, std::nullopt, {x}}}},
+ {OMPC_linear, omp::clause::Linear{{std::nullopt, std::nullopt, {x}}}},
};
omp::ConstructDecomposition Dec(AnyVersion, Helper, OMPD_simd, Clauses);
ASSERT_EQ(Dec.output.size(), 1u);
std::string Dir0 = stringify(Dec.output[0]);
- ASSERT_EQ(Dir0, "simd linear(, , , (x)) lastprivate(, (x))");
+ ASSERT_EQ(Dir0, "simd linear(, , (x)) lastprivate(, (x))");
}
} // namespace
More information about the flang-commits
mailing list