Skip to content

Commit 3e45edc

Browse files
committed
[flang][OpenMP] Parsing support for iterator modifiers in FROM and TO
Parse PRESENT modifier as well while we're at it (no MAPPER though). Add semantic checks for these clauses in the TARGET UPDATE construct, TODO messages in lowering.
1 parent 339c788 commit 3e45edc

22 files changed

+784
-40
lines changed

flang/include/flang/Evaluate/check-expression.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,10 @@ extern template std::optional<bool> IsContiguous(
115115
const CoarrayRef &, FoldingContext &);
116116
extern template std::optional<bool> IsContiguous(
117117
const Symbol &, FoldingContext &);
118+
static inline std::optional<bool> IsContiguous(const SymbolRef &s,
119+
FoldingContext &c) {
120+
return IsContiguous(s.get(), c);
121+
}
118122
template <typename A>
119123
bool IsSimplyContiguous(const A &x, FoldingContext &context) {
120124
return IsContiguous(x, context).value_or(false);

flang/include/flang/Parser/dump-parse-tree.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,8 @@ class ParseTreeDumper {
524524
NODE(parser, OmpEndCriticalDirective)
525525
NODE(parser, OmpEndLoopDirective)
526526
NODE(parser, OmpEndSectionsDirective)
527+
NODE(parser, OmpFromClause)
528+
NODE_ENUM(OmpFromClause, Expectation)
527529
NODE(parser, OmpIfClause)
528530
NODE_ENUM(OmpIfClause, DirectiveNameModifier)
529531
NODE_ENUM(OmpLastprivateClause, LastprivateModifier)
@@ -581,6 +583,9 @@ class ParseTreeDumper {
581583
NODE(parser, OmpSectionBlocks)
582584
NODE(parser, OmpSectionsDirective)
583585
NODE(parser, OmpSimpleStandaloneDirective)
586+
NODE(parser, OmpToClause)
587+
// No NODE_ENUM for OmpToClause::Expectation, because it's an alias
588+
// for OmpFromClause::Expectation.
584589
NODE(parser, Only)
585590
NODE(parser, OpenACCAtomicConstruct)
586591
NODE(parser, OpenACCBlockConstruct)

flang/include/flang/Parser/parse-tree.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3582,6 +3582,26 @@ struct OmpDeviceTypeClause {
35823582
WRAPPER_CLASS_BOILERPLATE(OmpDeviceTypeClause, Type);
35833583
};
35843584

3585+
// Ref: [4.5:107-109], [5.0:176-180], [5.1:205-210], [5.2:167-168]
3586+
//
3587+
// from-clause ->
3588+
// FROM(locator-list) |
3589+
// FROM(mapper-modifier: locator-list) | // since 5.0
3590+
// FROM(motion-modifier[,] ...: locator-list) // since 5.1
3591+
// motion-modifier ->
3592+
// PRESENT | mapper-modifier | iterator-modifier
3593+
struct OmpFromClause {
3594+
ENUM_CLASS(Expectation, Present);
3595+
TUPLE_CLASS_BOILERPLATE(OmpFromClause);
3596+
3597+
// As in the case of MAP, modifiers are parsed as lists, even if they
3598+
// are unique. These restrictions will be checked in semantic checks.
3599+
std::tuple<std::optional<std::list<Expectation>>,
3600+
std::optional<std::list<OmpIteratorModifier>>, OmpObjectList,
3601+
bool> // were the modifiers comma-separated?
3602+
t;
3603+
};
3604+
35853605
// OMP 5.2 12.6.1 grainsize-clause -> grainsize ([prescriptiveness :] value)
35863606
struct OmpGrainsizeClause {
35873607
TUPLE_CLASS_BOILERPLATE(OmpGrainsizeClause);
@@ -3718,6 +3738,28 @@ struct OmpScheduleClause {
37183738
t;
37193739
};
37203740

3741+
// Ref: [4.5:107-109], [5.0:176-180], [5.1:205-210], [5.2:167-168]
3742+
//
3743+
// to-clause (in DECLARE TARGET) ->
3744+
// TO(extended-list) | // until 5.1
3745+
// to-clause (in TARGET UPDATE) ->
3746+
// TO(locator-list) |
3747+
// TO(mapper-modifier: locator-list) | // since 5.0
3748+
// TO(motion-modifier[,] ...: locator-list) // since 5.1
3749+
// motion-modifier ->
3750+
// PRESENT | mapper-modifier | iterator-modifier
3751+
struct OmpToClause {
3752+
using Expectation = OmpFromClause::Expectation;
3753+
TUPLE_CLASS_BOILERPLATE(OmpToClause);
3754+
3755+
// As in the case of MAP, modifiers are parsed as lists, even if they
3756+
// are unique. These restrictions will be checked in semantic checks.
3757+
std::tuple<std::optional<std::list<Expectation>>,
3758+
std::optional<std::list<OmpIteratorModifier>>, OmpObjectList,
3759+
bool> // were the modifiers comma-separated?
3760+
t;
3761+
};
3762+
37213763
// OMP 5.2 12.6.2 num_tasks-clause -> num_tasks ([prescriptiveness :] value)
37223764
struct OmpNumTasksClause {
37233765
TUPLE_CLASS_BOILERPLATE(OmpNumTasksClause);

flang/lib/Lower/OpenMP/ClauseProcessor.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1019,8 +1019,15 @@ bool ClauseProcessor::processMotionClauses(lower::StatementContext &stmtCtx,
10191019

10201020
auto callbackFn = [&](const auto &clause, const parser::CharBlock &source) {
10211021
mlir::Location clauseLocation = converter.genLocation(source);
1022-
1022+
const auto &[expectation, mapper, iterator, objects] = clause.t;
10231023
// TODO Support motion modifiers: present, mapper, iterator.
1024+
if (expectation) {
1025+
TODO(clauseLocation, "PRESENT modifier is not supported yet");
1026+
} else if (mapper) {
1027+
TODO(clauseLocation, "Mapper modifier is not supported yet");
1028+
} else if (iterator) {
1029+
TODO(clauseLocation, "Iterator modifier is not supported yet");
1030+
}
10241031
constexpr llvm::omp::OpenMPOffloadMappingFlags mapTypeBits =
10251032
std::is_same_v<llvm::remove_cvref_t<decltype(clause)>, omp::clause::To>
10261033
? llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO

flang/lib/Lower/OpenMP/Clauses.cpp

Lines changed: 69 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -728,21 +728,51 @@ Firstprivate make(const parser::OmpClause::Firstprivate &inp,
728728

729729
From make(const parser::OmpClause::From &inp,
730730
semantics::SemanticsContext &semaCtx) {
731-
// inp.v -> parser::OmpObjectList
732-
return From{{/*Expectation=*/std::nullopt, /*Mapper=*/std::nullopt,
733-
/*Iterator=*/std::nullopt,
734-
/*LocatorList=*/makeObjects(inp.v, semaCtx)}};
731+
// inp.v -> parser::OmpFromClause
732+
using wrapped = parser::OmpFromClause;
733+
734+
CLAUSET_ENUM_CONVERT( //
735+
convert, parser::OmpFromClause::Expectation, From::Expectation,
736+
// clang-format off
737+
MS(Present, Present)
738+
// clang-format on
739+
);
740+
741+
auto &t0 = std::get<std::optional<std::list<wrapped::Expectation>>>(inp.v.t);
742+
auto &t1 =
743+
std::get<std::optional<std::list<parser::OmpIteratorModifier>>>(inp.v.t);
744+
auto &t2 = std::get<parser::OmpObjectList>(inp.v.t);
745+
746+
assert((!t0 || t0->size() == 1) && "Only one expectation modifier allowed");
747+
assert((!t1 || t1->size() == 1) && "Only one iterator modifier allowed");
748+
749+
auto expectation = [&]() -> std::optional<From::Expectation> {
750+
if (t0)
751+
return convert(t0->front());
752+
return std::nullopt;
753+
}();
754+
755+
auto iterator = [&]() -> std::optional<Iterator> {
756+
if (t1)
757+
return makeIterator(t1->front(), semaCtx);
758+
return std::nullopt;
759+
}();
760+
761+
return From{{/*Expectation=*/std::move(expectation), /*Mapper=*/std::nullopt,
762+
/*Iterator=*/std::move(iterator),
763+
/*LocatorList=*/makeObjects(t2, semaCtx)}};
735764
}
736765

737766
// Full: empty
738767

739768
Grainsize make(const parser::OmpClause::Grainsize &inp,
740-
semantics::SemanticsContext &semaCtx) {
769+
semantics::SemanticsContext &semaCtx) {
741770
// inp.v -> parser::OmpGrainsizeClause
742771
using wrapped = parser::OmpGrainsizeClause;
743772

744773
CLAUSET_ENUM_CONVERT( //
745-
convert, parser::OmpGrainsizeClause::Prescriptiveness, Grainsize::Prescriptiveness,
774+
convert, parser::OmpGrainsizeClause::Prescriptiveness,
775+
Grainsize::Prescriptiveness,
746776
// clang-format off
747777
MS(Strict, Strict)
748778
// clang-format on
@@ -1274,10 +1304,39 @@ ThreadLimit make(const parser::OmpClause::ThreadLimit &inp,
12741304

12751305
To make(const parser::OmpClause::To &inp,
12761306
semantics::SemanticsContext &semaCtx) {
1277-
// inp.v -> parser::OmpObjectList
1278-
return To{{/*Expectation=*/std::nullopt, /*Mapper=*/std::nullopt,
1279-
/*Iterator=*/std::nullopt,
1280-
/*LocatorList=*/makeObjects(inp.v, semaCtx)}};
1307+
// inp.v -> parser::OmpToClause
1308+
using wrapped = parser::OmpToClause;
1309+
1310+
CLAUSET_ENUM_CONVERT( //
1311+
convert, parser::OmpToClause::Expectation, To::Expectation,
1312+
// clang-format off
1313+
MS(Present, Present)
1314+
// clang-format on
1315+
);
1316+
1317+
auto &t0 = std::get<std::optional<std::list<wrapped::Expectation>>>(inp.v.t);
1318+
auto &t1 =
1319+
std::get<std::optional<std::list<parser::OmpIteratorModifier>>>(inp.v.t);
1320+
auto &t2 = std::get<parser::OmpObjectList>(inp.v.t);
1321+
1322+
assert((!t0 || t0->size() == 1) && "Only one expectation modifier allowed");
1323+
assert((!t1 || t1->size() == 1) && "Only one iterator modifier allowed");
1324+
1325+
auto expectation = [&]() -> std::optional<To::Expectation> {
1326+
if (t0)
1327+
return convert(t0->front());
1328+
return std::nullopt;
1329+
}();
1330+
1331+
auto iterator = [&]() -> std::optional<Iterator> {
1332+
if (t1)
1333+
return makeIterator(t1->front(), semaCtx);
1334+
return std::nullopt;
1335+
}();
1336+
1337+
return To{{/*Expectation=*/std::move(expectation), /*Mapper=*/std::nullopt,
1338+
/*Iterator=*/std::move(iterator),
1339+
/*LocatorList=*/makeObjects(t2, semaCtx)}};
12811340
}
12821341

12831342
// UnifiedAddress: empty

flang/lib/Parser/openmp-parsers.cpp

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,40 @@ template <typename Separator> struct MapModifiers {
122122
const Separator sep_;
123123
};
124124

125+
// This is almost exactly the same thing as MapModifiers. It has the same
126+
// issue (it expects modifiers in a specific order), and the fix for that
127+
// will change how modifiers are parsed. Instead of making this code more
128+
// generic, make it simple, and generalize after the fix is in place.
129+
template <typename Separator> struct MotionModifiers {
130+
constexpr MotionModifiers(Separator sep) : sep_(sep) {}
131+
constexpr MotionModifiers(const MotionModifiers &) = default;
132+
constexpr MotionModifiers(MotionModifiers &&) = default;
133+
134+
// Parsing of mappers if not implemented yet.
135+
using ExpParser = Parser<OmpFromClause::Expectation>;
136+
using IterParser = Parser<OmpIteratorModifier>;
137+
using ModParser = ConcatSeparated<Separator, ExpParser, IterParser>;
138+
139+
using resultType = typename ModParser::resultType;
140+
141+
std::optional<resultType> Parse(ParseState &state) const {
142+
auto mp = ModParser(sep_, ExpParser{}, IterParser{});
143+
auto mods = mp.Parse(state);
144+
// The ModParser always "succeeds", i.e. even if the input is junk, it
145+
// will return a tuple filled with nullopts. If any of the components
146+
// is not a nullopt, expect a ":".
147+
if (std::apply([](auto &&...opts) { return (... || !!opts); }, *mods)) {
148+
if (!attempt(":"_tok).Parse(state)) {
149+
return std::nullopt;
150+
}
151+
}
152+
return std::move(mods);
153+
}
154+
155+
private:
156+
const Separator sep_;
157+
};
158+
125159
// OpenMP Clauses
126160

127161
// [5.0] 2.1.6 iterator-specifier -> type-declaration-stmt = subscript-triple |
@@ -382,6 +416,31 @@ TYPE_CONTEXT_PARSER("Omp Depend clause"_en_US,
382416
maybe(Parser<OmpIteratorModifier>{} / ","_tok),
383417
Parser<OmpTaskDependenceType>{} / ":", Parser<OmpObjectList>{})))
384418

419+
TYPE_PARSER(construct<OmpFromClause::Expectation>(
420+
"PRESENT" >> pure(OmpFromClause::Expectation::Present)))
421+
422+
template <typename MotionClause, bool CommasEverywhere>
423+
static inline MotionClause makeMotionClause(
424+
std::tuple<std::optional<std::list<typename MotionClause::Expectation>>,
425+
std::optional<std::list<OmpIteratorModifier>>> &&mods,
426+
OmpObjectList &&objs) {
427+
auto &&[exp, iter] = std::move(mods);
428+
return MotionClause(
429+
std::move(exp), std::move(iter), std::move(objs), CommasEverywhere);
430+
}
431+
432+
TYPE_PARSER(construct<OmpFromClause>(
433+
applyFunction<OmpFromClause>(makeMotionClause<OmpFromClause, true>,
434+
MotionModifiers(","_tok), Parser<OmpObjectList>{}) ||
435+
applyFunction<OmpFromClause>(makeMotionClause<OmpFromClause, false>,
436+
MotionModifiers(maybe(","_tok)), Parser<OmpObjectList>{})))
437+
438+
TYPE_PARSER(construct<OmpToClause>(
439+
applyFunction<OmpToClause>(makeMotionClause<OmpToClause, true>,
440+
MotionModifiers(","_tok), Parser<OmpObjectList>{}) ||
441+
applyFunction<OmpToClause>(makeMotionClause<OmpToClause, false>,
442+
MotionModifiers(maybe(","_tok)), Parser<OmpObjectList>{})))
443+
385444
// 2.15.3.7 LINEAR (linear-list: linear-step)
386445
// linear-list -> list | modifier(list)
387446
// linear-modifier -> REF | VAL | UVAL
@@ -475,11 +534,11 @@ TYPE_PARSER(
475534
parenthesized(scalarIntExpr))) ||
476535
"FINAL" >> construct<OmpClause>(construct<OmpClause::Final>(
477536
parenthesized(scalarLogicalExpr))) ||
478-
"FULL" >> construct<OmpClause>(construct<OmpClause::Full>()) ||
479537
"FIRSTPRIVATE" >> construct<OmpClause>(construct<OmpClause::Firstprivate>(
480538
parenthesized(Parser<OmpObjectList>{}))) ||
481539
"FROM" >> construct<OmpClause>(construct<OmpClause::From>(
482-
parenthesized(Parser<OmpObjectList>{}))) ||
540+
parenthesized(Parser<OmpFromClause>{}))) ||
541+
"FULL" >> construct<OmpClause>(construct<OmpClause::Full>()) ||
483542
"GRAINSIZE" >> construct<OmpClause>(construct<OmpClause::Grainsize>(
484543
parenthesized(Parser<OmpGrainsizeClause>{}))) ||
485544
"HAS_DEVICE_ADDR" >>
@@ -554,7 +613,7 @@ TYPE_PARSER(
554613
"THREAD_LIMIT" >> construct<OmpClause>(construct<OmpClause::ThreadLimit>(
555614
parenthesized(scalarIntExpr))) ||
556615
"TO" >> construct<OmpClause>(construct<OmpClause::To>(
557-
parenthesized(Parser<OmpObjectList>{}))) ||
616+
parenthesized(Parser<OmpToClause>{}))) ||
558617
"USE_DEVICE_PTR" >> construct<OmpClause>(construct<OmpClause::UseDevicePtr>(
559618
parenthesized(Parser<OmpObjectList>{}))) ||
560619
"USE_DEVICE_ADDR" >>

flang/lib/Parser/unparse.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2138,6 +2138,27 @@ class UnparseVisitor {
21382138
Put(",");
21392139
Walk(std::get<std::optional<ScalarIntConstantExpr>>(x.t));
21402140
}
2141+
void Unparse(const OmpFromClause &x) {
2142+
auto &expect =
2143+
std::get<std::optional<std::list<OmpFromClause::Expectation>>>(x.t);
2144+
auto &iter = std::get<std::optional<std::list<OmpIteratorModifier>>>(x.t);
2145+
bool needComma{false};
2146+
if (expect) {
2147+
Walk(*expect);
2148+
needComma = true;
2149+
}
2150+
if (iter) {
2151+
if (needComma) {
2152+
Put(", ");
2153+
}
2154+
Walk(*iter);
2155+
needComma = true;
2156+
}
2157+
if (needComma) {
2158+
Put(": ");
2159+
}
2160+
Walk(std::get<OmpObjectList>(x.t));
2161+
}
21412162
void Unparse(const OmpIfClause &x) {
21422163
Walk(std::get<std::optional<OmpIfClause::DirectiveNameModifier>>(x.t), ":");
21432164
Walk(std::get<ScalarLogicalExpr>(x.t));
@@ -2241,6 +2262,27 @@ class UnparseVisitor {
22412262
Walk(":",
22422263
std::get<std::optional<OmpDefaultmapClause::VariableCategory>>(x.t));
22432264
}
2265+
void Unparse(const OmpToClause &x) {
2266+
auto &expect =
2267+
std::get<std::optional<std::list<OmpToClause::Expectation>>>(x.t);
2268+
auto &iter = std::get<std::optional<std::list<OmpIteratorModifier>>>(x.t);
2269+
bool needComma{false};
2270+
if (expect) {
2271+
Walk(*expect);
2272+
needComma = true;
2273+
}
2274+
if (iter) {
2275+
if (needComma) {
2276+
Put(", ");
2277+
}
2278+
Walk(*iter);
2279+
needComma = true;
2280+
}
2281+
if (needComma) {
2282+
Put(": ");
2283+
}
2284+
Walk(std::get<OmpObjectList>(x.t));
2285+
}
22442286
#define GEN_FLANG_CLAUSE_UNPARSE
22452287
#include "llvm/Frontend/OpenMP/OMP.inc"
22462288
void Unparse(const OmpLoopDirective &x) {
@@ -2858,6 +2900,7 @@ class UnparseVisitor {
28582900
WALK_NESTED_ENUM(OmpDeviceTypeClause, Type) // OMP DEVICE_TYPE
28592901
WALK_NESTED_ENUM(
28602902
OmpReductionClause, ReductionModifier) // OMP reduction-modifier
2903+
WALK_NESTED_ENUM(OmpFromClause, Expectation) // OMP motion-expectation
28612904
WALK_NESTED_ENUM(OmpIfClause, DirectiveNameModifier) // OMP directive-modifier
28622905
WALK_NESTED_ENUM(OmpCancelType, Type) // OMP cancel-type
28632906
WALK_NESTED_ENUM(OmpOrderClause, Type) // OMP order-type

0 commit comments

Comments
 (0)