Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions flang/include/flang/Evaluate/check-expression.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@ extern template std::optional<bool> IsContiguous(
const CoarrayRef &, FoldingContext &);
extern template std::optional<bool> IsContiguous(
const Symbol &, FoldingContext &);
static inline std::optional<bool> IsContiguous(
const SymbolRef &s, FoldingContext &c) {
return IsContiguous(s.get(), c);
}
template <typename A>
bool IsSimplyContiguous(const A &x, FoldingContext &context) {
return IsContiguous(x, context).value_or(false);
Expand Down
5 changes: 5 additions & 0 deletions flang/include/flang/Parser/dump-parse-tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,8 @@ class ParseTreeDumper {
NODE(parser, OmpEndCriticalDirective)
NODE(parser, OmpEndLoopDirective)
NODE(parser, OmpEndSectionsDirective)
NODE(parser, OmpFromClause)
NODE_ENUM(OmpFromClause, Expectation)
NODE(parser, OmpIfClause)
NODE_ENUM(OmpIfClause, DirectiveNameModifier)
NODE_ENUM(OmpLastprivateClause, LastprivateModifier)
Expand Down Expand Up @@ -581,6 +583,9 @@ class ParseTreeDumper {
NODE(parser, OmpSectionBlocks)
NODE(parser, OmpSectionsDirective)
NODE(parser, OmpSimpleStandaloneDirective)
NODE(parser, OmpToClause)
// No NODE_ENUM for OmpToClause::Expectation, because it's an alias
// for OmpFromClause::Expectation.
NODE(parser, Only)
NODE(parser, OpenACCAtomicConstruct)
NODE(parser, OpenACCBlockConstruct)
Expand Down
42 changes: 42 additions & 0 deletions flang/include/flang/Parser/parse-tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -3582,6 +3582,26 @@ struct OmpDeviceTypeClause {
WRAPPER_CLASS_BOILERPLATE(OmpDeviceTypeClause, Type);
};

// Ref: [4.5:107-109], [5.0:176-180], [5.1:205-210], [5.2:167-168]
//
// from-clause ->
// FROM(locator-list) |
// FROM(mapper-modifier: locator-list) | // since 5.0
// FROM(motion-modifier[,] ...: locator-list) // since 5.1
// motion-modifier ->
// PRESENT | mapper-modifier | iterator-modifier
struct OmpFromClause {
ENUM_CLASS(Expectation, Present);
TUPLE_CLASS_BOILERPLATE(OmpFromClause);

// As in the case of MAP, modifiers are parsed as lists, even if they
// are unique. These restrictions will be checked in semantic checks.
std::tuple<std::optional<std::list<Expectation>>,
std::optional<std::list<OmpIteratorModifier>>, OmpObjectList,
bool> // were the modifiers comma-separated?
t;
};

// OMP 5.2 12.6.1 grainsize-clause -> grainsize ([prescriptiveness :] value)
struct OmpGrainsizeClause {
TUPLE_CLASS_BOILERPLATE(OmpGrainsizeClause);
Expand Down Expand Up @@ -3718,6 +3738,28 @@ struct OmpScheduleClause {
t;
};

// Ref: [4.5:107-109], [5.0:176-180], [5.1:205-210], [5.2:167-168]
//
// to-clause (in DECLARE TARGET) ->
// TO(extended-list) | // until 5.1
// to-clause (in TARGET UPDATE) ->
// TO(locator-list) |
// TO(mapper-modifier: locator-list) | // since 5.0
// TO(motion-modifier[,] ...: locator-list) // since 5.1
// motion-modifier ->
// PRESENT | mapper-modifier | iterator-modifier
struct OmpToClause {
using Expectation = OmpFromClause::Expectation;
TUPLE_CLASS_BOILERPLATE(OmpToClause);

// As in the case of MAP, modifiers are parsed as lists, even if they
// are unique. These restrictions will be checked in semantic checks.
std::tuple<std::optional<std::list<Expectation>>,
std::optional<std::list<OmpIteratorModifier>>, OmpObjectList,
bool> // were the modifiers comma-separated?
t;
};

// OMP 5.2 12.6.2 num_tasks-clause -> num_tasks ([prescriptiveness :] value)
struct OmpNumTasksClause {
TUPLE_CLASS_BOILERPLATE(OmpNumTasksClause);
Expand Down
14 changes: 10 additions & 4 deletions flang/lib/Lower/OpenMP/ClauseProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1019,16 +1019,22 @@ bool ClauseProcessor::processMotionClauses(lower::StatementContext &stmtCtx,

auto callbackFn = [&](const auto &clause, const parser::CharBlock &source) {
mlir::Location clauseLocation = converter.genLocation(source);

const auto &[expectation, mapper, iterator, objects] = clause.t;
// TODO Support motion modifiers: present, mapper, iterator.
if (expectation) {
TODO(clauseLocation, "PRESENT modifier is not supported yet");
} else if (mapper) {
TODO(clauseLocation, "Mapper modifier is not supported yet");
} else if (iterator) {
TODO(clauseLocation, "Iterator modifier is not supported yet");
}
constexpr llvm::omp::OpenMPOffloadMappingFlags mapTypeBits =
std::is_same_v<llvm::remove_cvref_t<decltype(clause)>, omp::clause::To>
? llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO
: llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM;

processMapObjects(stmtCtx, clauseLocation, std::get<ObjectList>(clause.t),
mapTypeBits, parentMemberIndices, result.mapVars,
mapSymbols);
processMapObjects(stmtCtx, clauseLocation, objects, mapTypeBits,
parentMemberIndices, result.mapVars, mapSymbols);
};

bool clauseFound = findRepeatableClause<omp::clause::To>(callbackFn);
Expand Down
79 changes: 69 additions & 10 deletions flang/lib/Lower/OpenMP/Clauses.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -728,21 +728,51 @@ Firstprivate make(const parser::OmpClause::Firstprivate &inp,

From make(const parser::OmpClause::From &inp,
semantics::SemanticsContext &semaCtx) {
// inp.v -> parser::OmpObjectList
return From{{/*Expectation=*/std::nullopt, /*Mapper=*/std::nullopt,
/*Iterator=*/std::nullopt,
/*LocatorList=*/makeObjects(inp.v, semaCtx)}};
// inp.v -> parser::OmpFromClause
using wrapped = parser::OmpFromClause;

CLAUSET_ENUM_CONVERT( //
convert, parser::OmpFromClause::Expectation, From::Expectation,
// clang-format off
MS(Present, Present)
// clang-format on
);

auto &t0 = std::get<std::optional<std::list<wrapped::Expectation>>>(inp.v.t);
auto &t1 =
std::get<std::optional<std::list<parser::OmpIteratorModifier>>>(inp.v.t);
auto &t2 = std::get<parser::OmpObjectList>(inp.v.t);

assert((!t0 || t0->size() == 1) && "Only one expectation modifier allowed");
assert((!t1 || t1->size() == 1) && "Only one iterator modifier allowed");

auto expectation = [&]() -> std::optional<From::Expectation> {
if (t0)
return convert(t0->front());
return std::nullopt;
}();

auto iterator = [&]() -> std::optional<Iterator> {
if (t1)
return makeIterator(t1->front(), semaCtx);
return std::nullopt;
}();

return From{{/*Expectation=*/std::move(expectation), /*Mapper=*/std::nullopt,
/*Iterator=*/std::move(iterator),
/*LocatorList=*/makeObjects(t2, semaCtx)}};
}

// Full: empty

Grainsize make(const parser::OmpClause::Grainsize &inp,
semantics::SemanticsContext &semaCtx) {
semantics::SemanticsContext &semaCtx) {
// inp.v -> parser::OmpGrainsizeClause
using wrapped = parser::OmpGrainsizeClause;

CLAUSET_ENUM_CONVERT( //
convert, parser::OmpGrainsizeClause::Prescriptiveness, Grainsize::Prescriptiveness,
convert, parser::OmpGrainsizeClause::Prescriptiveness,
Grainsize::Prescriptiveness,
// clang-format off
MS(Strict, Strict)
// clang-format on
Expand Down Expand Up @@ -1274,10 +1304,39 @@ ThreadLimit make(const parser::OmpClause::ThreadLimit &inp,

To make(const parser::OmpClause::To &inp,
semantics::SemanticsContext &semaCtx) {
// inp.v -> parser::OmpObjectList
return To{{/*Expectation=*/std::nullopt, /*Mapper=*/std::nullopt,
/*Iterator=*/std::nullopt,
/*LocatorList=*/makeObjects(inp.v, semaCtx)}};
// inp.v -> parser::OmpToClause
using wrapped = parser::OmpToClause;

CLAUSET_ENUM_CONVERT( //
convert, parser::OmpToClause::Expectation, To::Expectation,
// clang-format off
MS(Present, Present)
// clang-format on
);

auto &t0 = std::get<std::optional<std::list<wrapped::Expectation>>>(inp.v.t);
auto &t1 =
std::get<std::optional<std::list<parser::OmpIteratorModifier>>>(inp.v.t);
auto &t2 = std::get<parser::OmpObjectList>(inp.v.t);

assert((!t0 || t0->size() == 1) && "Only one expectation modifier allowed");
assert((!t1 || t1->size() == 1) && "Only one iterator modifier allowed");

auto expectation = [&]() -> std::optional<To::Expectation> {
if (t0)
return convert(t0->front());
return std::nullopt;
}();

auto iterator = [&]() -> std::optional<Iterator> {
if (t1)
return makeIterator(t1->front(), semaCtx);
return std::nullopt;
}();

return To{{/*Expectation=*/std::move(expectation), /*Mapper=*/std::nullopt,
/*Iterator=*/std::move(iterator),
/*LocatorList=*/makeObjects(t2, semaCtx)}};
}

// UnifiedAddress: empty
Expand Down
65 changes: 62 additions & 3 deletions flang/lib/Parser/openmp-parsers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,40 @@ template <typename Separator> struct MapModifiers {
const Separator sep_;
};

// This is almost exactly the same thing as MapModifiers. It has the same
// issue (it expects modifiers in a specific order), and the fix for that
// will change how modifiers are parsed. Instead of making this code more
// generic, make it simple, and generalize after the fix is in place.
template <typename Separator> struct MotionModifiers {
constexpr MotionModifiers(Separator sep) : sep_(sep) {}
constexpr MotionModifiers(const MotionModifiers &) = default;
constexpr MotionModifiers(MotionModifiers &&) = default;

// Parsing of mappers if not implemented yet.
using ExpParser = Parser<OmpFromClause::Expectation>;
using IterParser = Parser<OmpIteratorModifier>;
using ModParser = ConcatSeparated<Separator, ExpParser, IterParser>;

using resultType = typename ModParser::resultType;

std::optional<resultType> Parse(ParseState &state) const {
auto mp = ModParser(sep_, ExpParser{}, IterParser{});
auto mods = mp.Parse(state);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Braced initialization.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

// The ModParser always "succeeds", i.e. even if the input is junk, it
// will return a tuple filled with nullopts. If any of the components
// is not a nullopt, expect a ":".
if (std::apply([](auto &&...opts) { return (... || !!opts); }, *mods)) {
if (!attempt(":"_tok).Parse(state)) {
return std::nullopt;
}
}
return std::move(mods);
}

private:
const Separator sep_;
};

// OpenMP Clauses

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

TYPE_PARSER(construct<OmpFromClause::Expectation>(
"PRESENT" >> pure(OmpFromClause::Expectation::Present)))

template <typename MotionClause, bool CommasEverywhere>
static inline MotionClause makeMotionClause(
std::tuple<std::optional<std::list<typename MotionClause::Expectation>>,
std::optional<std::list<OmpIteratorModifier>>> &&mods,
OmpObjectList &&objs) {
auto &&[exp, iter] = std::move(mods);
return MotionClause(
std::move(exp), std::move(iter), std::move(objs), CommasEverywhere);
}

TYPE_PARSER(construct<OmpFromClause>(
applyFunction<OmpFromClause>(makeMotionClause<OmpFromClause, true>,
MotionModifiers(","_tok), Parser<OmpObjectList>{}) ||
applyFunction<OmpFromClause>(makeMotionClause<OmpFromClause, false>,
MotionModifiers(maybe(","_tok)), Parser<OmpObjectList>{})))

TYPE_PARSER(construct<OmpToClause>(
applyFunction<OmpToClause>(makeMotionClause<OmpToClause, true>,
MotionModifiers(","_tok), Parser<OmpObjectList>{}) ||
applyFunction<OmpToClause>(makeMotionClause<OmpToClause, false>,
MotionModifiers(maybe(","_tok)), Parser<OmpObjectList>{})))

// 2.15.3.7 LINEAR (linear-list: linear-step)
// linear-list -> list | modifier(list)
// linear-modifier -> REF | VAL | UVAL
Expand Down Expand Up @@ -475,11 +534,11 @@ TYPE_PARSER(
parenthesized(scalarIntExpr))) ||
"FINAL" >> construct<OmpClause>(construct<OmpClause::Final>(
parenthesized(scalarLogicalExpr))) ||
"FULL" >> construct<OmpClause>(construct<OmpClause::Full>()) ||
"FIRSTPRIVATE" >> construct<OmpClause>(construct<OmpClause::Firstprivate>(
parenthesized(Parser<OmpObjectList>{}))) ||
"FROM" >> construct<OmpClause>(construct<OmpClause::From>(
parenthesized(Parser<OmpObjectList>{}))) ||
parenthesized(Parser<OmpFromClause>{}))) ||
"FULL" >> construct<OmpClause>(construct<OmpClause::Full>()) ||
"GRAINSIZE" >> construct<OmpClause>(construct<OmpClause::Grainsize>(
parenthesized(Parser<OmpGrainsizeClause>{}))) ||
"HAS_DEVICE_ADDR" >>
Expand Down Expand Up @@ -554,7 +613,7 @@ TYPE_PARSER(
"THREAD_LIMIT" >> construct<OmpClause>(construct<OmpClause::ThreadLimit>(
parenthesized(scalarIntExpr))) ||
"TO" >> construct<OmpClause>(construct<OmpClause::To>(
parenthesized(Parser<OmpObjectList>{}))) ||
parenthesized(Parser<OmpToClause>{}))) ||
"USE_DEVICE_PTR" >> construct<OmpClause>(construct<OmpClause::UseDevicePtr>(
parenthesized(Parser<OmpObjectList>{}))) ||
"USE_DEVICE_ADDR" >>
Expand Down
43 changes: 43 additions & 0 deletions flang/lib/Parser/unparse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2138,6 +2138,27 @@ class UnparseVisitor {
Put(",");
Walk(std::get<std::optional<ScalarIntConstantExpr>>(x.t));
}
void Unparse(const OmpFromClause &x) {
auto &expect =
std::get<std::optional<std::list<OmpFromClause::Expectation>>>(x.t);
auto &iter = std::get<std::optional<std::list<OmpIteratorModifier>>>(x.t);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: braced initialization.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

bool needComma{false};
if (expect) {
Walk(*expect);
needComma = true;
}
if (iter) {
if (needComma) {
Put(", ");
}
Walk(*iter);
needComma = true;
}
if (needComma) {
Put(": ");
}
Walk(std::get<OmpObjectList>(x.t));
}
void Unparse(const OmpIfClause &x) {
Walk(std::get<std::optional<OmpIfClause::DirectiveNameModifier>>(x.t), ":");
Walk(std::get<ScalarLogicalExpr>(x.t));
Expand Down Expand Up @@ -2241,6 +2262,27 @@ class UnparseVisitor {
Walk(":",
std::get<std::optional<OmpDefaultmapClause::VariableCategory>>(x.t));
}
void Unparse(const OmpToClause &x) {
auto &expect =
std::get<std::optional<std::list<OmpToClause::Expectation>>>(x.t);
auto &iter = std::get<std::optional<std::list<OmpIteratorModifier>>>(x.t);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: braced initialisation

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

bool needComma{false};
if (expect) {
Walk(*expect);
needComma = true;
}
if (iter) {
if (needComma) {
Put(", ");
}
Walk(*iter);
needComma = true;
}
if (needComma) {
Put(": ");
}
Walk(std::get<OmpObjectList>(x.t));
}
#define GEN_FLANG_CLAUSE_UNPARSE
#include "llvm/Frontend/OpenMP/OMP.inc"
void Unparse(const OmpLoopDirective &x) {
Expand Down Expand Up @@ -2858,6 +2900,7 @@ class UnparseVisitor {
WALK_NESTED_ENUM(OmpDeviceTypeClause, Type) // OMP DEVICE_TYPE
WALK_NESTED_ENUM(
OmpReductionClause, ReductionModifier) // OMP reduction-modifier
WALK_NESTED_ENUM(OmpFromClause, Expectation) // OMP motion-expectation
WALK_NESTED_ENUM(OmpIfClause, DirectiveNameModifier) // OMP directive-modifier
WALK_NESTED_ENUM(OmpCancelType, Type) // OMP cancel-type
WALK_NESTED_ENUM(OmpOrderClause, Type) // OMP order-type
Expand Down
Loading
Loading