Skip to content

Commit

Permalink
[flang][OpenMP] Rework LINEAR clause (llvm#119278)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
kparzysz authored Dec 12, 2024
1 parent 58f9c4f commit 03cbe42
Show file tree
Hide file tree
Showing 18 changed files with 448 additions and 233 deletions.
3 changes: 1 addition & 2 deletions flang/examples/FeatureList/FeatureList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
5 changes: 3 additions & 2 deletions flang/include/flang/Parser/dump-parse-tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -559,10 +559,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)
Expand Down
34 changes: 0 additions & 34 deletions flang/include/flang/Parser/parse-tree-visitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
56 changes: 32 additions & 24 deletions flang/include/flang/Parser/parse-tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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]
Expand All @@ -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]
Expand Down Expand Up @@ -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]
Expand Down
2 changes: 2 additions & 0 deletions flang/include/flang/Semantics/openmp-modifiers.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
37 changes: 16 additions & 21 deletions flang/lib/Lower/OpenMP/Clauses.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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,
Expand Down
63 changes: 56 additions & 7 deletions flang/lib/Parser/openmp-parsers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down Expand Up @@ -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) ||
Expand Down Expand Up @@ -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>{}) ||
Expand Down Expand Up @@ -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>{}))
Expand Down
62 changes: 56 additions & 6 deletions flang/lib/Parser/unparse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading

0 comments on commit 03cbe42

Please sign in to comment.