mirror of
https://github.com/intel/llvm.git
synced 2026-01-16 05:32:28 +08:00
[flang][OpenMP] Rework LINEAR clause (#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.
This commit is contained in:
committed by
GitHub
parent
58f9c4fc00
commit
03cbe42627
@@ -495,8 +495,7 @@ public:
|
||||
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)
|
||||
|
||||
@@ -559,10 +559,11 @@ public:
|
||||
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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -3699,6 +3699,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
|
||||
@@ -3934,7 +3950,7 @@ struct OmpFailClause {
|
||||
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]
|
||||
@@ -3981,28 +3997,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]
|
||||
@@ -4017,7 +4025,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]
|
||||
@@ -4105,7 +4113,7 @@ struct OmpTaskReductionClause {
|
||||
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]
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -899,8 +899,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
|
||||
@@ -910,26 +908,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,
|
||||
|
||||
@@ -99,6 +99,25 @@ 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 {
|
||||
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 +251,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) ||
|
||||
@@ -288,6 +312,11 @@ TYPE_PARSER(sourced(construct<OmpInReductionClause::Modifier>(
|
||||
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>{}) ||
|
||||
@@ -471,13 +500,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<OmpLinearClause>(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>{}))
|
||||
|
||||
@@ -2133,13 +2133,63 @@ public:
|
||||
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;
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -3669,17 +3652,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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3692,73 +3721,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);
|
||||
symbol->name());
|
||||
}
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
// 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(
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -502,19 +502,8 @@ public:
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
117
flang/test/Parser/OpenMP/linear-clause.f90
Normal file
117
flang/test/Parser/OpenMP/linear-clause.f90
Normal file
@@ -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
|
||||
@@ -221,11 +221,19 @@ use omp_lib
|
||||
|
||||
!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
|
||||
|
||||
@@ -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
|
||||
|
||||
13
flang/test/Semantics/OpenMP/linear-clause02.f90
Normal file
13
flang/test/Semantics/OpenMP/linear-clause02.f90
Normal file
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user