Skip to content

Commit 973fa98

Browse files
authored
[flang][OpenMP] Parse iterators, add to MAP clause, TODO for lowering (#113167)
Define `OmpIteratorSpecifier` and `OmpIteratorModifier` parser classes, and add parsing for them. Those are reusable between any clauses that use iterator modifiers. Add support for iterator modifiers to the MAP clause up to lowering, where a TODO message is emitted.
1 parent 1f9953c commit 973fa98

File tree

16 files changed

+768
-142
lines changed

16 files changed

+768
-142
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,8 @@ class ParseTreeDumper {
474474
NODE(parser, NullInit)
475475
NODE(parser, ObjectDecl)
476476
NODE(parser, OldParameterStmt)
477+
NODE(parser, OmpIteratorSpecifier)
478+
NODE(parser, OmpIteratorModifier)
477479
NODE(parser, OmpAlignedClause)
478480
NODE(parser, OmpAtomic)
479481
NODE(parser, OmpAtomicCapture)

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

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3424,7 +3424,17 @@ struct AssignedGotoStmt {
34243424

34253425
WRAPPER_CLASS(PauseStmt, std::optional<StopCode>);
34263426

3427-
// Parse tree nodes for OpenMP 4.5 directives and clauses
3427+
// Parse tree nodes for OpenMP 5.2 directives and clauses
3428+
3429+
// [5.0] 2.1.6 iterator-specifier -> type-declaration-stmt = subscript-triple
3430+
// iterator-modifier -> iterator-specifier-list
3431+
struct OmpIteratorSpecifier {
3432+
TUPLE_CLASS_BOILERPLATE(OmpIteratorSpecifier);
3433+
CharBlock source;
3434+
std::tuple<TypeDeclarationStmt, SubscriptTriplet> t;
3435+
};
3436+
3437+
WRAPPER_CLASS(OmpIteratorModifier, std::list<OmpIteratorSpecifier>);
34283438

34293439
// 2.5 proc-bind-clause -> PROC_BIND (MASTER | CLOSE | SPREAD)
34303440
struct OmpProcBindClause {
@@ -3450,16 +3460,25 @@ struct OmpObject {
34503460
WRAPPER_CLASS(OmpObjectList, std::list<OmpObject>);
34513461

34523462
// 2.15.5.1 map ->
3453-
// MAP ([ [map-type-modifiers [,] ] map-type : ] variable-name-list)
3454-
// map-type-modifiers -> map-type-modifier [,] [...]
3463+
// MAP ([[map-type-modifier-list [,]] [iterator-modifier [,]] map-type : ]
3464+
// variable-name-list)
3465+
// map-type-modifier-list -> map-type-modifier [,] [...]
34553466
// map-type-modifier -> ALWAYS | CLOSE | PRESENT | OMPX_HOLD
34563467
// map-type -> TO | FROM | TOFROM | ALLOC | RELEASE | DELETE
34573468
struct OmpMapClause {
34583469
ENUM_CLASS(TypeModifier, Always, Close, Present, Ompx_Hold);
34593470
ENUM_CLASS(Type, To, From, Tofrom, Alloc, Release, Delete)
34603471
TUPLE_CLASS_BOILERPLATE(OmpMapClause);
3461-
std::tuple<std::optional<std::list<TypeModifier>>, std::optional<Type>,
3462-
OmpObjectList>
3472+
3473+
// All modifiers are parsed into optional lists, even if they are unique.
3474+
// The checks for satisfying those constraints are deferred to semantics.
3475+
// In OpenMP 5.2 the non-comma syntax has been deprecated: keep the
3476+
// information about separator presence to emit a diagnostic if needed.
3477+
std::tuple<std::optional<std::list<TypeModifier>>,
3478+
std::optional<std::list<OmpIteratorModifier>>, // unique
3479+
std::optional<std::list<Type>>, // unique
3480+
OmpObjectList,
3481+
bool> // were the modifiers comma-separated?
34633482
t;
34643483
};
34653484

flang/include/flang/Semantics/scope.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ class Scope {
6161
public:
6262
ENUM_CLASS(Kind, Global, IntrinsicModules, Module, MainProgram, Subprogram,
6363
BlockData, DerivedType, BlockConstruct, Forall, OtherConstruct,
64-
OpenACCConstruct, ImpliedDos)
64+
OpenACCConstruct, ImpliedDos, OtherClause)
6565
using ImportKind = common::ImportKind;
6666

6767
// Create the Global scope -- the root of the scope tree

flang/lib/Lower/OpenMP/ClauseProcessor.cpp

Lines changed: 56 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -936,57 +936,64 @@ bool ClauseProcessor::processMap(
936936
llvm::SmallVector<OmpMapMemberIndicesData>>
937937
parentMemberIndices;
938938

939-
bool clauseFound = findRepeatableClause<omp::clause::Map>(
940-
[&](const omp::clause::Map &clause, const parser::CharBlock &source) {
941-
using Map = omp::clause::Map;
942-
mlir::Location clauseLocation = converter.genLocation(source);
943-
const auto &mapType = std::get<std::optional<Map::MapType>>(clause.t);
944-
llvm::omp::OpenMPOffloadMappingFlags mapTypeBits =
945-
llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_NONE;
946-
// If the map type is specified, then process it else Tofrom is the
947-
// default.
948-
Map::MapType type = mapType.value_or(Map::MapType::Tofrom);
949-
switch (type) {
950-
case Map::MapType::To:
951-
mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO;
952-
break;
953-
case Map::MapType::From:
954-
mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM;
955-
break;
956-
case Map::MapType::Tofrom:
957-
mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO |
958-
llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM;
959-
break;
960-
case Map::MapType::Alloc:
961-
case Map::MapType::Release:
962-
// alloc and release is the default map_type for the Target Data
963-
// Ops, i.e. if no bits for map_type is supplied then alloc/release
964-
// is implicitly assumed based on the target directive. Default
965-
// value for Target Data and Enter Data is alloc and for Exit Data
966-
// it is release.
967-
break;
968-
case Map::MapType::Delete:
969-
mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_DELETE;
970-
}
939+
auto process = [&](const omp::clause::Map &clause,
940+
const parser::CharBlock &source) {
941+
using Map = omp::clause::Map;
942+
mlir::Location clauseLocation = converter.genLocation(source);
943+
const auto &mapType = std::get<std::optional<Map::MapType>>(clause.t);
944+
llvm::omp::OpenMPOffloadMappingFlags mapTypeBits =
945+
llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_NONE;
946+
// If the map type is specified, then process it else Tofrom is the
947+
// default.
948+
Map::MapType type = mapType.value_or(Map::MapType::Tofrom);
949+
switch (type) {
950+
case Map::MapType::To:
951+
mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO;
952+
break;
953+
case Map::MapType::From:
954+
mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM;
955+
break;
956+
case Map::MapType::Tofrom:
957+
mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO |
958+
llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM;
959+
break;
960+
case Map::MapType::Alloc:
961+
case Map::MapType::Release:
962+
// alloc and release is the default map_type for the Target Data
963+
// Ops, i.e. if no bits for map_type is supplied then alloc/release
964+
// is implicitly assumed based on the target directive. Default
965+
// value for Target Data and Enter Data is alloc and for Exit Data
966+
// it is release.
967+
break;
968+
case Map::MapType::Delete:
969+
mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_DELETE;
970+
}
971971

972-
auto &modTypeMods =
973-
std::get<std::optional<Map::MapTypeModifiers>>(clause.t);
974-
if (modTypeMods) {
975-
if (llvm::is_contained(*modTypeMods, Map::MapTypeModifier::Always))
976-
mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_ALWAYS;
977-
// Diagnose unimplemented map-type-modifiers.
978-
if (llvm::any_of(*modTypeMods, [](Map::MapTypeModifier m) {
979-
return m != Map::MapTypeModifier::Always;
980-
})) {
981-
TODO(currentLocation, "Map type modifiers (other than 'ALWAYS')"
982-
" are not implemented yet");
983-
}
984-
}
985-
processMapObjects(stmtCtx, clauseLocation,
986-
std::get<omp::ObjectList>(clause.t), mapTypeBits,
987-
parentMemberIndices, result.mapVars, *ptrMapSyms);
988-
});
972+
auto &modTypeMods =
973+
std::get<std::optional<Map::MapTypeModifiers>>(clause.t);
974+
if (modTypeMods) {
975+
if (llvm::is_contained(*modTypeMods, Map::MapTypeModifier::Always))
976+
mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_ALWAYS;
977+
// Diagnose unimplemented map-type-modifiers.
978+
if (llvm::any_of(*modTypeMods, [](Map::MapTypeModifier m) {
979+
return m != Map::MapTypeModifier::Always;
980+
})) {
981+
TODO(currentLocation, "Map type modifiers (other than 'ALWAYS')"
982+
" are not implemented yet");
983+
}
984+
}
985+
986+
if (std::get<std::optional<omp::clause::Iterator>>(clause.t)) {
987+
TODO(currentLocation,
988+
"Support for iterator modifiers is not implemented yet");
989+
}
990+
991+
processMapObjects(stmtCtx, clauseLocation,
992+
std::get<omp::ObjectList>(clause.t), mapTypeBits,
993+
parentMemberIndices, result.mapVars, *ptrMapSyms);
994+
};
989995

996+
bool clauseFound = findRepeatableClause<omp::clause::Map>(process);
990997
insertChildMapInfoIntoParent(converter, parentMemberIndices, result.mapVars,
991998
*ptrMapSyms);
992999

flang/lib/Lower/OpenMP/Clauses.cpp

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,46 @@ MAKE_INCOMPLETE_CLASS(Match, Match);
232232
// MAKE_INCOMPLETE_CLASS(Otherwise, ); // missing-in-parser
233233
MAKE_INCOMPLETE_CLASS(When, When);
234234

235+
List<IteratorSpecifier>
236+
makeIteratorSpecifiers(const parser::OmpIteratorSpecifier &inp,
237+
semantics::SemanticsContext &semaCtx) {
238+
List<IteratorSpecifier> specifiers;
239+
240+
auto &[begin, end, step] = std::get<parser::SubscriptTriplet>(inp.t).t;
241+
assert(begin && end && "Expecting begin/end values");
242+
evaluate::ExpressionAnalyzer ea{semaCtx};
243+
244+
MaybeExpr rbegin{ea.Analyze(*begin)}, rend{ea.Analyze(*end)};
245+
MaybeExpr rstep;
246+
if (step)
247+
rstep = ea.Analyze(*step);
248+
249+
assert(rbegin && rend && "Unable to get range bounds");
250+
Range range{{*rbegin, *rend, rstep}};
251+
252+
auto &tds = std::get<parser::TypeDeclarationStmt>(inp.t);
253+
auto &entities = std::get<std::list<parser::EntityDecl>>(tds.t);
254+
for (const parser::EntityDecl &ed : entities) {
255+
auto &name = std::get<parser::ObjectName>(ed.t);
256+
assert(name.symbol && "Expecting symbol for iterator variable");
257+
auto *stype = name.symbol->GetType();
258+
assert(stype && "Expecting symbol type");
259+
IteratorSpecifier spec{{evaluate::DynamicType::From(*stype),
260+
makeObject(name, semaCtx), range}};
261+
specifiers.emplace_back(std::move(spec));
262+
}
263+
264+
return specifiers;
265+
}
266+
267+
Iterator makeIterator(const parser::OmpIteratorModifier &inp,
268+
semantics::SemanticsContext &semaCtx) {
269+
Iterator iterator;
270+
for (auto &&spec : inp.v)
271+
llvm::append_range(iterator, makeIteratorSpecifiers(spec, semaCtx));
272+
return iterator;
273+
}
274+
235275
DefinedOperator makeDefinedOperator(const parser::DefinedOperator &inp,
236276
semantics::SemanticsContext &semaCtx) {
237277
CLAUSET_ENUM_CONVERT( //
@@ -851,10 +891,24 @@ Map make(const parser::OmpClause::Map &inp,
851891
);
852892

853893
auto &t0 = std::get<std::optional<std::list<wrapped::TypeModifier>>>(inp.v.t);
854-
auto &t1 = std::get<std::optional<wrapped::Type>>(inp.v.t);
855-
auto &t2 = std::get<parser::OmpObjectList>(inp.v.t);
894+
auto &t1 =
895+
std::get<std::optional<std::list<parser::OmpIteratorModifier>>>(inp.v.t);
896+
auto &t2 = std::get<std::optional<std::list<wrapped::Type>>>(inp.v.t);
897+
auto &t3 = std::get<parser::OmpObjectList>(inp.v.t);
898+
899+
// These should have been diagnosed already.
900+
assert((!t1 || t1->size() == 1) && "Only one iterator modifier is allowed");
901+
assert((!t2 || t2->size() == 1) && "Only one map type is allowed");
902+
903+
auto iterator = [&]() -> std::optional<Iterator> {
904+
if (t1)
905+
return makeIterator(t1->front(), semaCtx);
906+
return std::nullopt;
907+
}();
856908

857-
std::optional<Map::MapType> maybeType = maybeApply(convert1, t1);
909+
std::optional<Map::MapType> maybeType;
910+
if (t2)
911+
maybeType = maybeApply(convert1, std::optional<wrapped::Type>(t2->front()));
858912

859913
std::optional<Map::MapTypeModifiers> maybeTypeMods = maybeApply(
860914
[&](const std::list<wrapped::TypeModifier> &typeMods) {
@@ -867,8 +921,8 @@ Map make(const parser::OmpClause::Map &inp,
867921

868922
return Map{{/*MapType=*/maybeType,
869923
/*MapTypeModifiers=*/maybeTypeMods,
870-
/*Mapper=*/std::nullopt, /*Iterator=*/std::nullopt,
871-
/*LocatorList=*/makeObjects(t2, semaCtx)}};
924+
/*Mapper=*/std::nullopt, /*Iterator=*/std::move(iterator),
925+
/*LocatorList=*/makeObjects(t3, semaCtx)}};
872926
}
873927

874928
// Match: incomplete

flang/lib/Lower/OpenMP/Clauses.h

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#define FORTRAN_LOWER_OPENMP_CLAUSES_H
1010

1111
#include "flang/Evaluate/expression.h"
12+
#include "flang/Evaluate/type.h"
1213
#include "flang/Parser/parse-tree.h"
1314
#include "flang/Semantics/expression.h"
1415
#include "flang/Semantics/semantics.h"
@@ -29,12 +30,7 @@ namespace Fortran::lower::omp {
2930
using namespace Fortran;
3031
using SomeExpr = semantics::SomeExpr;
3132
using MaybeExpr = semantics::MaybeExpr;
32-
33-
// evaluate::SomeType doesn't provide == operation. It's not really used in
34-
// flang's clauses so far, so a trivial implementation is sufficient.
35-
struct TypeTy : public evaluate::SomeType {
36-
bool operator==(const TypeTy &t) const { return true; }
37-
};
33+
using TypeTy = evaluate::DynamicType;
3834

3935
template <typename ExprTy>
4036
struct IdTyTemplate {
@@ -150,6 +146,9 @@ std::optional<Object> getBaseObject(const Object &object,
150146
semantics::SemanticsContext &semaCtx);
151147

152148
namespace clause {
149+
using Range = tomp::type::RangeT<ExprTy>;
150+
using Iterator = tomp::type::IteratorT<TypeTy, IdTy, ExprTy>;
151+
using IteratorSpecifier = tomp::type::IteratorSpecifierT<TypeTy, IdTy, ExprTy>;
153152
using DefinedOperator = tomp::type::DefinedOperatorT<IdTy, ExprTy>;
154153
using ProcedureDesignator = tomp::type::ProcedureDesignatorT<IdTy, ExprTy>;
155154
using ReductionOperator = tomp::type::ReductionIdentifierT<IdTy, ExprTy>;

0 commit comments

Comments
 (0)