[flang][OpenMP] Sema checks, lowering with new format of MAP modifiers (#149137)
OpenMP 6.0 has changed the modifiers on the MAP clause. Previous patch has introduced parsing support for them. This patch introduces processing of the new forms in semantic checks and in lowering. This only applies to existing modifiers, which were updated in the 6.0 spec. Any of the newly introduced modifiers (SELF and REF) are ignored.
This commit is contained in:
parent
b692b239f0
commit
2914a488c7
@ -812,9 +812,8 @@ public:
|
||||
// OpenMP data-sharing attribute
|
||||
OmpShared, OmpPrivate, OmpLinear, OmpFirstPrivate, OmpLastPrivate,
|
||||
// OpenMP data-mapping attribute
|
||||
OmpMapTo, OmpMapFrom, OmpMapToFrom, OmpMapAlloc, OmpMapRelease,
|
||||
OmpMapDelete, OmpUseDevicePtr, OmpUseDeviceAddr, OmpIsDevicePtr,
|
||||
OmpHasDeviceAddr,
|
||||
OmpMapTo, OmpMapFrom, OmpMapToFrom, OmpMapStorage, OmpMapDelete,
|
||||
OmpUseDevicePtr, OmpUseDeviceAddr, OmpIsDevicePtr, OmpHasDeviceAddr,
|
||||
// OpenMP data-copying attribute
|
||||
OmpCopyIn, OmpCopyPrivate,
|
||||
// OpenMP miscellaneous flags
|
||||
|
@ -1315,7 +1315,8 @@ bool ClauseProcessor::processMap(
|
||||
const parser::CharBlock &source) {
|
||||
using Map = omp::clause::Map;
|
||||
mlir::Location clauseLocation = converter.genLocation(source);
|
||||
const auto &[mapType, typeMods, mappers, iterator, objects] = clause.t;
|
||||
const auto &[mapType, typeMods, refMod, mappers, iterator, objects] =
|
||||
clause.t;
|
||||
llvm::omp::OpenMPOffloadMappingFlags mapTypeBits =
|
||||
llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_NONE;
|
||||
std::string mapperIdName = "__implicit_mapper";
|
||||
@ -1342,16 +1343,13 @@ bool ClauseProcessor::processMap(
|
||||
mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO |
|
||||
llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM;
|
||||
break;
|
||||
case Map::MapType::Alloc:
|
||||
case Map::MapType::Release:
|
||||
case Map::MapType::Storage:
|
||||
// alloc and release is the default map_type for the Target Data
|
||||
// Ops, i.e. if no bits for map_type is supplied then alloc/release
|
||||
// is implicitly assumed based on the target directive. Default
|
||||
// value for Target Data and Enter Data is alloc and for Exit Data
|
||||
// it is release.
|
||||
// (aka storage in 6.0+) is implicitly assumed based on the target
|
||||
// directive. Default value for Target Data and Enter Data is alloc
|
||||
// and for Exit Data it is release.
|
||||
break;
|
||||
case Map::MapType::Delete:
|
||||
mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_DELETE;
|
||||
}
|
||||
|
||||
if (typeMods) {
|
||||
@ -1362,6 +1360,8 @@ bool ClauseProcessor::processMap(
|
||||
mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_PRESENT;
|
||||
if (llvm::is_contained(*typeMods, Map::MapTypeModifier::Close))
|
||||
mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_CLOSE;
|
||||
if (llvm::is_contained(*typeMods, Map::MapTypeModifier::Delete))
|
||||
mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_DELETE;
|
||||
if (llvm::is_contained(*typeMods, Map::MapTypeModifier::OmpxHold))
|
||||
mapTypeBits |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_OMPX_HOLD;
|
||||
}
|
||||
|
@ -1001,19 +1001,21 @@ Map make(const parser::OmpClause::Map &inp,
|
||||
semantics::SemanticsContext &semaCtx) {
|
||||
// inp.v -> parser::OmpMapClause
|
||||
CLAUSET_ENUM_CONVERT( //
|
||||
convert1, parser::OmpMapType::Value, Map::MapType,
|
||||
convertMapType, parser::OmpMapType::Value, Map::MapType,
|
||||
// clang-format off
|
||||
MS(Alloc, Alloc)
|
||||
MS(Delete, Delete)
|
||||
MS(From, From)
|
||||
MS(Release, Release)
|
||||
MS(To, To)
|
||||
MS(Tofrom, Tofrom)
|
||||
MS(Alloc, Storage)
|
||||
MS(Delete, Storage)
|
||||
MS(Release, Storage)
|
||||
MS(Storage, Storage)
|
||||
MS(From, From)
|
||||
MS(To, To)
|
||||
MS(Tofrom, Tofrom)
|
||||
// clang-format on
|
||||
);
|
||||
|
||||
CLAUSET_ENUM_CONVERT( //
|
||||
convert2, parser::OmpMapTypeModifier::Value, Map::MapTypeModifier,
|
||||
convertMapTypeMod, parser::OmpMapTypeModifier::Value,
|
||||
Map::MapTypeModifier,
|
||||
// clang-format off
|
||||
MS(Always, Always)
|
||||
MS(Close, Close)
|
||||
@ -1022,43 +1024,76 @@ Map make(const parser::OmpClause::Map &inp,
|
||||
// clang-format on
|
||||
);
|
||||
|
||||
CLAUSET_ENUM_CONVERT( //
|
||||
convertRefMod, parser::OmpRefModifier::Value, Map::RefModifier,
|
||||
// clang-format off
|
||||
MS(Ref_Ptee, RefPtee)
|
||||
MS(Ref_Ptr, RefPtr)
|
||||
MS(Ref_Ptr_Ptee, RefPtrPtee)
|
||||
// clang-format on
|
||||
);
|
||||
|
||||
// Treat always, close, present, self, delete modifiers as map-type-
|
||||
// modifiers.
|
||||
auto &mods = semantics::OmpGetModifiers(inp.v);
|
||||
auto *t1 = semantics::OmpGetUniqueModifier<parser::OmpMapper>(mods);
|
||||
auto *t2 = semantics::OmpGetUniqueModifier<parser::OmpIterator>(mods);
|
||||
auto *t3 = semantics::OmpGetUniqueModifier<parser::OmpMapType>(mods);
|
||||
auto &t4 = std::get<parser::OmpObjectList>(inp.v.t);
|
||||
|
||||
auto *t1 = semantics::OmpGetUniqueModifier<parser::OmpMapType>(mods);
|
||||
auto &t2 = std::get<parser::OmpObjectList>(inp.v.t);
|
||||
|
||||
auto type = [&]() -> std::optional<Map::MapType> {
|
||||
if (t1)
|
||||
return convertMapType(t1->v);
|
||||
return std::nullopt;
|
||||
}();
|
||||
|
||||
llvm::DenseSet<Map::MapTypeModifier> modSet;
|
||||
if (t1 && t1->v == parser::OmpMapType::Value::Delete)
|
||||
modSet.insert(Map::MapTypeModifier::Delete);
|
||||
|
||||
for (auto *typeMod :
|
||||
semantics::OmpGetRepeatableModifier<parser::OmpMapTypeModifier>(mods)) {
|
||||
modSet.insert(convertMapTypeMod(typeMod->v));
|
||||
}
|
||||
if (semantics::OmpGetUniqueModifier<parser::OmpAlwaysModifier>(mods))
|
||||
modSet.insert(Map::MapTypeModifier::Always);
|
||||
if (semantics::OmpGetUniqueModifier<parser::OmpCloseModifier>(mods))
|
||||
modSet.insert(Map::MapTypeModifier::Close);
|
||||
if (semantics::OmpGetUniqueModifier<parser::OmpDeleteModifier>(mods))
|
||||
modSet.insert(Map::MapTypeModifier::Delete);
|
||||
if (semantics::OmpGetUniqueModifier<parser::OmpPresentModifier>(mods))
|
||||
modSet.insert(Map::MapTypeModifier::Present);
|
||||
if (semantics::OmpGetUniqueModifier<parser::OmpSelfModifier>(mods))
|
||||
modSet.insert(Map::MapTypeModifier::Self);
|
||||
if (semantics::OmpGetUniqueModifier<parser::OmpxHoldModifier>(mods))
|
||||
modSet.insert(Map::MapTypeModifier::OmpxHold);
|
||||
|
||||
std::optional<Map::MapTypeModifiers> maybeTypeMods{};
|
||||
if (!modSet.empty())
|
||||
maybeTypeMods = Map::MapTypeModifiers(modSet.begin(), modSet.end());
|
||||
|
||||
auto refMod = [&]() -> std::optional<Map::RefModifier> {
|
||||
if (auto *t = semantics::OmpGetUniqueModifier<parser::OmpRefModifier>(mods))
|
||||
return convertRefMod(t->v);
|
||||
return std::nullopt;
|
||||
}();
|
||||
|
||||
auto mappers = [&]() -> std::optional<List<Mapper>> {
|
||||
if (t1)
|
||||
return List<Mapper>{Mapper{makeObject(t1->v, semaCtx)}};
|
||||
if (auto *t = semantics::OmpGetUniqueModifier<parser::OmpMapper>(mods))
|
||||
return List<Mapper>{Mapper{makeObject(t->v, semaCtx)}};
|
||||
return std::nullopt;
|
||||
}();
|
||||
|
||||
auto iterator = [&]() -> std::optional<Iterator> {
|
||||
if (t2)
|
||||
return makeIterator(*t2, semaCtx);
|
||||
if (auto *t = semantics::OmpGetUniqueModifier<parser::OmpIterator>(mods))
|
||||
return makeIterator(*t, semaCtx);
|
||||
return std::nullopt;
|
||||
}();
|
||||
|
||||
auto type = [&]() -> std::optional<Map::MapType> {
|
||||
if (t3)
|
||||
return convert1(t3->v);
|
||||
return std::nullopt;
|
||||
}();
|
||||
|
||||
Map::MapTypeModifiers typeMods;
|
||||
for (auto *typeMod :
|
||||
semantics::OmpGetRepeatableModifier<parser::OmpMapTypeModifier>(mods)) {
|
||||
typeMods.push_back(convert2(typeMod->v));
|
||||
}
|
||||
std::optional<Map::MapTypeModifiers> maybeTypeMods{};
|
||||
if (!typeMods.empty())
|
||||
maybeTypeMods = std::move(typeMods);
|
||||
|
||||
return Map{{/*MapType=*/std::move(type),
|
||||
/*MapTypeModifiers=*/std::move(maybeTypeMods),
|
||||
/*Mapper=*/std::move(mappers), /*Iterator=*/std::move(iterator),
|
||||
/*LocatorList=*/makeObjects(t4, semaCtx)}};
|
||||
/*RefModifier=*/std::move(refMod), /*Mapper=*/std::move(mappers),
|
||||
/*Iterator=*/std::move(iterator),
|
||||
/*LocatorList=*/makeObjects(t2, semaCtx)}};
|
||||
}
|
||||
|
||||
Match make(const parser::OmpClause::Match &inp,
|
||||
|
@ -27,7 +27,8 @@ class CanonicalizationOfOmp {
|
||||
public:
|
||||
template <typename T> bool Pre(T &) { return true; }
|
||||
template <typename T> void Post(T &) {}
|
||||
CanonicalizationOfOmp(parser::Messages &messages) : messages_{messages} {}
|
||||
CanonicalizationOfOmp(SemanticsContext &context)
|
||||
: context_{context}, messages_{context.messages()} {}
|
||||
|
||||
void Post(parser::Block &block) {
|
||||
for (auto it{block.begin()}; it != block.end(); ++it) {
|
||||
@ -401,6 +402,11 @@ private:
|
||||
// if the specified OpenMP version is less than 6.0, rewrite the affected
|
||||
// modifiers back into the pre-6.0 forms.
|
||||
void CanonicalizeMapModifiers(parser::OmpMapClause &map) {
|
||||
unsigned version{context_.langOptions().OpenMPVersion};
|
||||
if (version >= 60) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Omp{Always, Close, Present, xHold}Modifier -> OmpMapTypeModifier
|
||||
// OmpDeleteModifier -> OmpMapType
|
||||
using Modifier = parser::OmpMapClause::Modifier;
|
||||
@ -432,12 +438,13 @@ private:
|
||||
// same construct. This is for converting utility constructs to executable
|
||||
// constructs.
|
||||
std::map<parser::SpecificationPart *, parser::Block *> blockForSpec_;
|
||||
SemanticsContext &context_;
|
||||
parser::Messages &messages_;
|
||||
};
|
||||
|
||||
bool CanonicalizeOmp(parser::Messages &messages, parser::Program &program) {
|
||||
CanonicalizationOfOmp omp{messages};
|
||||
bool CanonicalizeOmp(SemanticsContext &context, parser::Program &program) {
|
||||
CanonicalizationOfOmp omp{context};
|
||||
Walk(program, omp);
|
||||
return !messages.AnyFatalError();
|
||||
return !context.messages().AnyFatalError();
|
||||
}
|
||||
} // namespace Fortran::semantics
|
||||
|
@ -11,13 +11,12 @@
|
||||
|
||||
namespace Fortran::parser {
|
||||
struct Program;
|
||||
class Messages;
|
||||
} // namespace Fortran::parser
|
||||
}
|
||||
|
||||
namespace Fortran::semantics {
|
||||
class SemanticsContext;
|
||||
|
||||
bool CanonicalizeOmp(parser::Messages &messages, parser::Program &program);
|
||||
bool CanonicalizeOmp(SemanticsContext &context, parser::Program &program);
|
||||
} // namespace Fortran::semantics
|
||||
|
||||
#endif // FORTRAN_SEMANTICS_CANONICALIZE_OMP_H_
|
||||
|
@ -37,6 +37,7 @@
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/Frontend/OpenMP/OMP.h"
|
||||
|
||||
@ -3398,23 +3399,22 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Detach &x) {
|
||||
}
|
||||
}
|
||||
|
||||
void OmpStructureChecker::CheckAllowedMapTypes(
|
||||
const parser::OmpMapType::Value &type,
|
||||
const std::list<parser::OmpMapType::Value> &allowedMapTypeList) {
|
||||
if (!llvm::is_contained(allowedMapTypeList, type)) {
|
||||
std::string commaSeparatedMapTypes;
|
||||
llvm::interleave(
|
||||
allowedMapTypeList.begin(), allowedMapTypeList.end(),
|
||||
[&](const parser::OmpMapType::Value &mapType) {
|
||||
commaSeparatedMapTypes.append(parser::ToUpperCaseLetters(
|
||||
parser::OmpMapType::EnumToString(mapType)));
|
||||
},
|
||||
[&] { commaSeparatedMapTypes.append(", "); });
|
||||
context_.Say(GetContext().clauseSource,
|
||||
"Only the %s map types are permitted "
|
||||
"for MAP clauses on the %s directive"_err_en_US,
|
||||
commaSeparatedMapTypes, ContextDirectiveAsFortran());
|
||||
void OmpStructureChecker::CheckAllowedMapTypes(parser::OmpMapType::Value type,
|
||||
llvm::ArrayRef<parser::OmpMapType::Value> allowed) {
|
||||
if (llvm::is_contained(allowed, type)) {
|
||||
return;
|
||||
}
|
||||
|
||||
llvm::SmallVector<std::string> names;
|
||||
llvm::transform(
|
||||
allowed, std::back_inserter(names), [](parser::OmpMapType::Value val) {
|
||||
return parser::ToUpperCaseLetters(
|
||||
parser::OmpMapType::EnumToString(val));
|
||||
});
|
||||
llvm::sort(names);
|
||||
context_.Say(GetContext().clauseSource,
|
||||
"Only the %s map types are permitted for MAP clauses on the %s directive"_err_en_US,
|
||||
llvm::join(names, ", "), ContextDirectiveAsFortran());
|
||||
}
|
||||
|
||||
void OmpStructureChecker::Enter(const parser::OmpClause::Map &x) {
|
||||
@ -3435,27 +3435,62 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Map &x) {
|
||||
CheckIteratorModifier(*iter);
|
||||
}
|
||||
if (auto *type{OmpGetUniqueModifier<parser::OmpMapType>(modifiers)}) {
|
||||
using Directive = llvm::omp::Directive;
|
||||
using Value = parser::OmpMapType::Value;
|
||||
switch (GetContext().directive) {
|
||||
case llvm::omp::Directive::OMPD_target:
|
||||
case llvm::omp::Directive::OMPD_target_teams:
|
||||
case llvm::omp::Directive::OMPD_target_teams_distribute:
|
||||
case llvm::omp::Directive::OMPD_target_teams_distribute_simd:
|
||||
case llvm::omp::Directive::OMPD_target_teams_distribute_parallel_do:
|
||||
case llvm::omp::Directive::OMPD_target_teams_distribute_parallel_do_simd:
|
||||
case llvm::omp::Directive::OMPD_target_data:
|
||||
CheckAllowedMapTypes(
|
||||
type->v, {Value::To, Value::From, Value::Tofrom, Value::Alloc});
|
||||
break;
|
||||
case llvm::omp::Directive::OMPD_target_enter_data:
|
||||
CheckAllowedMapTypes(type->v, {Value::To, Value::Alloc});
|
||||
break;
|
||||
case llvm::omp::Directive::OMPD_target_exit_data:
|
||||
CheckAllowedMapTypes(
|
||||
type->v, {Value::From, Value::Release, Value::Delete});
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
static auto isValidForVersion{
|
||||
[](parser::OmpMapType::Value t, unsigned version) {
|
||||
switch (t) {
|
||||
case parser::OmpMapType::Value::Alloc:
|
||||
case parser::OmpMapType::Value::Delete:
|
||||
case parser::OmpMapType::Value::Release:
|
||||
return version < 60;
|
||||
case parser::OmpMapType::Value::Storage:
|
||||
return version >= 60;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}};
|
||||
|
||||
llvm::SmallVector<parser::OmpMapType::Value> mapEnteringTypes{[&]() {
|
||||
llvm::SmallVector<parser::OmpMapType::Value> result;
|
||||
for (size_t i{0}; i != parser::OmpMapType::Value_enumSize; ++i) {
|
||||
auto t{static_cast<parser::OmpMapType::Value>(i)};
|
||||
if (isValidForVersion(t, version) && IsMapEnteringType(t)) {
|
||||
result.push_back(t);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}()};
|
||||
llvm::SmallVector<parser::OmpMapType::Value> mapExitingTypes{[&]() {
|
||||
llvm::SmallVector<parser::OmpMapType::Value> result;
|
||||
for (size_t i{0}; i != parser::OmpMapType::Value_enumSize; ++i) {
|
||||
auto t{static_cast<parser::OmpMapType::Value>(i)};
|
||||
if (isValidForVersion(t, version) && IsMapExitingType(t)) {
|
||||
result.push_back(t);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}()};
|
||||
|
||||
llvm::omp::Directive dir{GetContext().directive};
|
||||
llvm::ArrayRef<llvm::omp::Directive> leafs{
|
||||
llvm::omp::getLeafConstructsOrSelf(dir)};
|
||||
|
||||
if (llvm::is_contained(leafs, Directive::OMPD_target) ||
|
||||
llvm::is_contained(leafs, Directive::OMPD_target_data)) {
|
||||
if (version >= 60) {
|
||||
// Map types listed in the decay table. [6.0:276]
|
||||
CheckAllowedMapTypes(
|
||||
type->v, {Value::Storage, Value::From, Value::To, Value::Tofrom});
|
||||
} else {
|
||||
CheckAllowedMapTypes(
|
||||
type->v, {Value::Alloc, Value::From, Value::To, Value::Tofrom});
|
||||
}
|
||||
} else if (llvm::is_contained(leafs, Directive::OMPD_target_enter_data)) {
|
||||
CheckAllowedMapTypes(type->v, mapEnteringTypes);
|
||||
} else if (llvm::is_contained(leafs, Directive::OMPD_target_exit_data)) {
|
||||
CheckAllowedMapTypes(type->v, mapExitingTypes);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -179,8 +179,8 @@ private:
|
||||
void HasInvalidDistributeNesting(const parser::OpenMPLoopConstruct &x);
|
||||
void HasInvalidLoopBinding(const parser::OpenMPLoopConstruct &x);
|
||||
// specific clause related
|
||||
void CheckAllowedMapTypes(const parser::OmpMapType::Value &,
|
||||
const std::list<parser::OmpMapType::Value> &);
|
||||
void CheckAllowedMapTypes(
|
||||
parser::OmpMapType::Value, llvm::ArrayRef<parser::OmpMapType::Value>);
|
||||
|
||||
const std::list<parser::OmpTraitProperty> &GetTraitPropertyList(
|
||||
const parser::OmpTraitSelector &);
|
||||
|
@ -143,6 +143,31 @@ bool IsVarOrFunctionRef(const MaybeExpr &expr) {
|
||||
}
|
||||
}
|
||||
|
||||
bool IsMapEnteringType(parser::OmpMapType::Value type) {
|
||||
switch (type) {
|
||||
case parser::OmpMapType::Value::Alloc:
|
||||
case parser::OmpMapType::Value::Storage:
|
||||
case parser::OmpMapType::Value::To:
|
||||
case parser::OmpMapType::Value::Tofrom:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsMapExitingType(parser::OmpMapType::Value type) {
|
||||
switch (type) {
|
||||
case parser::OmpMapType::Value::Delete:
|
||||
case parser::OmpMapType::Value::From:
|
||||
case parser::OmpMapType::Value::Release:
|
||||
case parser::OmpMapType::Value::Storage:
|
||||
case parser::OmpMapType::Value::Tofrom:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<SomeExpr> GetEvaluateExpr(const parser::Expr &parserExpr) {
|
||||
const parser::TypedExpr &typedExpr{parserExpr.typedExpr};
|
||||
// ForwardOwningPointer typedExpr
|
||||
|
@ -59,6 +59,9 @@ bool IsExtendedListItem(const Symbol &sym);
|
||||
bool IsVariableListItem(const Symbol &sym);
|
||||
bool IsVarOrFunctionRef(const MaybeExpr &expr);
|
||||
|
||||
bool IsMapEnteringType(parser::OmpMapType::Value type);
|
||||
bool IsMapExitingType(parser::OmpMapType::Value type);
|
||||
|
||||
std::optional<SomeExpr> GetEvaluateExpr(const parser::Expr &parserExpr);
|
||||
std::optional<evaluate::DynamicType> GetDynamicType(
|
||||
const parser::Expr &parserExpr);
|
||||
|
@ -727,7 +727,9 @@ public:
|
||||
void Post(const parser::EorLabel &eorLabel) { CheckSourceLabel(eorLabel.v); }
|
||||
|
||||
void Post(const parser::OmpMapClause &x) {
|
||||
Symbol::Flag ompFlag = Symbol::Flag::OmpMapToFrom;
|
||||
unsigned version{context_.langOptions().OpenMPVersion};
|
||||
std::optional<Symbol::Flag> ompFlag;
|
||||
|
||||
auto &mods{OmpGetModifiers(x)};
|
||||
if (auto *mapType{OmpGetUniqueModifier<parser::OmpMapType>(mods)}) {
|
||||
switch (mapType->v) {
|
||||
@ -741,10 +743,9 @@ public:
|
||||
ompFlag = Symbol::Flag::OmpMapToFrom;
|
||||
break;
|
||||
case parser::OmpMapType::Value::Alloc:
|
||||
ompFlag = Symbol::Flag::OmpMapAlloc;
|
||||
break;
|
||||
case parser::OmpMapType::Value::Release:
|
||||
ompFlag = Symbol::Flag::OmpMapRelease;
|
||||
case parser::OmpMapType::Value::Storage:
|
||||
ompFlag = Symbol::Flag::OmpMapStorage;
|
||||
break;
|
||||
case parser::OmpMapType::Value::Delete:
|
||||
ompFlag = Symbol::Flag::OmpMapDelete;
|
||||
@ -753,6 +754,24 @@ public:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ompFlag) {
|
||||
if (version >= 60) {
|
||||
// [6.0:275:12-15]
|
||||
// When a map-type is not specified for a clause on which it may be
|
||||
// specified, the map-type defaults to storage if the delete-modifier
|
||||
// is present on the clause or if the list item for which the map-type
|
||||
// is not specified is an assumed-size array.
|
||||
if (OmpGetUniqueModifier<parser::OmpDeleteModifier>(mods)) {
|
||||
ompFlag = Symbol::Flag::OmpMapStorage;
|
||||
}
|
||||
// Otherwise, if delete-modifier is absent, leave ompFlag unset.
|
||||
} else {
|
||||
// [5.2:151:10]
|
||||
// If a map-type is not specified, the map-type defaults to tofrom.
|
||||
ompFlag = Symbol::Flag::OmpMapToFrom;
|
||||
}
|
||||
}
|
||||
|
||||
const auto &ompObjList{std::get<parser::OmpObjectList>(x.t)};
|
||||
for (const auto &ompObj : ompObjList.v) {
|
||||
common::visit(
|
||||
@ -761,15 +780,15 @@ public:
|
||||
if (const auto *name{
|
||||
semantics::getDesignatorNameIfDataRef(designator)}) {
|
||||
if (name->symbol) {
|
||||
name->symbol->set(ompFlag);
|
||||
AddToContextObjectWithDSA(*name->symbol, ompFlag);
|
||||
}
|
||||
if (name->symbol &&
|
||||
semantics::IsAssumedSizeArray(*name->symbol)) {
|
||||
context_.Say(designator.source,
|
||||
"Assumed-size whole arrays may not appear on the %s "
|
||||
"clause"_err_en_US,
|
||||
"MAP");
|
||||
name->symbol->set(
|
||||
ompFlag.value_or(Symbol::Flag::OmpMapStorage));
|
||||
AddToContextObjectWithDSA(*name->symbol, *ompFlag);
|
||||
if (semantics::IsAssumedSizeArray(*name->symbol)) {
|
||||
context_.Say(designator.source,
|
||||
"Assumed-size whole arrays may not appear on the %s "
|
||||
"clause"_err_en_US,
|
||||
"MAP");
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -777,7 +796,7 @@ public:
|
||||
},
|
||||
ompObj.u);
|
||||
|
||||
ResolveOmpObject(ompObj, ompFlag);
|
||||
ResolveOmpObject(ompObj, ompFlag.value_or(Symbol::Flag::OmpMapStorage));
|
||||
}
|
||||
}
|
||||
|
||||
@ -2776,9 +2795,8 @@ void OmpAttributeVisitor::ResolveOmpObject(
|
||||
}
|
||||
Symbol::Flag dataMappingAttributeFlags[] = {
|
||||
Symbol::Flag::OmpMapTo, Symbol::Flag::OmpMapFrom,
|
||||
Symbol::Flag::OmpMapToFrom, Symbol::Flag::OmpMapAlloc,
|
||||
Symbol::Flag::OmpMapRelease, Symbol::Flag::OmpMapDelete,
|
||||
Symbol::Flag::OmpIsDevicePtr,
|
||||
Symbol::Flag::OmpMapToFrom, Symbol::Flag::OmpMapStorage,
|
||||
Symbol::Flag::OmpMapDelete, Symbol::Flag::OmpIsDevicePtr,
|
||||
Symbol::Flag::OmpHasDeviceAddr};
|
||||
|
||||
Symbol::Flag dataSharingAttributeFlags[] = {
|
||||
|
@ -642,8 +642,7 @@ bool Semantics::Perform() {
|
||||
return ValidateLabels(context_, program_) &&
|
||||
parser::CanonicalizeDo(program_) && // force line break
|
||||
CanonicalizeAcc(context_.messages(), program_) &&
|
||||
CanonicalizeOmp(context_.messages(), program_) &&
|
||||
CanonicalizeCUDA(program_) &&
|
||||
CanonicalizeOmp(context_, program_) && CanonicalizeCUDA(program_) &&
|
||||
PerformStatementSemantics(context_, program_) &&
|
||||
CanonicalizeDirectives(context_.messages(), program_) &&
|
||||
ModFileWriter{context_}
|
||||
|
@ -861,8 +861,7 @@ std::string Symbol::OmpFlagToClauseName(Symbol::Flag ompFlag) {
|
||||
case Symbol::Flag::OmpMapTo:
|
||||
case Symbol::Flag::OmpMapFrom:
|
||||
case Symbol::Flag::OmpMapToFrom:
|
||||
case Symbol::Flag::OmpMapAlloc:
|
||||
case Symbol::Flag::OmpMapRelease:
|
||||
case Symbol::Flag::OmpMapStorage:
|
||||
case Symbol::Flag::OmpMapDelete:
|
||||
clauseName = "MAP";
|
||||
break;
|
||||
|
@ -1,4 +1,6 @@
|
||||
! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=51 %s -o - | FileCheck %s
|
||||
! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=52 %s -o - | FileCheck %s
|
||||
! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=60 %s -o - | FileCheck %s
|
||||
|
||||
subroutine map_present_target_data
|
||||
integer :: x
|
||||
@ -15,6 +17,14 @@ subroutine map_present_update
|
||||
!$omp target update to(present: x)
|
||||
end subroutine
|
||||
|
||||
subroutine map_always
|
||||
integer :: x
|
||||
!CHECK: %[[MAP:.*]] = omp.map.info {{.*}} map_clauses(always, tofrom) {{.*}} {name = "x"}
|
||||
!CHECK: omp.target_data map_entries(%[[MAP]] : {{.*}}) {
|
||||
!$omp target data map(always, tofrom: x)
|
||||
!$omp end target data
|
||||
end subroutine
|
||||
|
||||
subroutine map_close
|
||||
integer :: x
|
||||
!CHECK: %[[MAP:.*]] = omp.map.info {{.*}} map_clauses(close, tofrom) {{.*}} {name = "x"}
|
||||
|
@ -207,7 +207,7 @@ program main
|
||||
enddo
|
||||
!$omp end target teams
|
||||
|
||||
!ERROR: Only the TO, FROM, TOFROM, ALLOC map types are permitted for MAP clauses on the TARGET TEAMS directive
|
||||
!ERROR: Only the ALLOC, FROM, TO, TOFROM map types are permitted for MAP clauses on the TARGET TEAMS directive
|
||||
!$omp target teams map(delete:a)
|
||||
do i = 1, N
|
||||
a(i) = 3.14
|
||||
@ -307,7 +307,7 @@ program main
|
||||
enddo
|
||||
!$omp end target teams distribute
|
||||
|
||||
!ERROR: Only the TO, FROM, TOFROM, ALLOC map types are permitted for MAP clauses on the TARGET TEAMS DISTRIBUTE directive
|
||||
!ERROR: Only the ALLOC, FROM, TO, TOFROM map types are permitted for MAP clauses on the TARGET TEAMS DISTRIBUTE directive
|
||||
!$omp target teams distribute map(delete:a)
|
||||
do i = 1, N
|
||||
a(i) = 3.14
|
||||
@ -400,7 +400,7 @@ program main
|
||||
enddo
|
||||
!$omp end target teams distribute parallel do
|
||||
|
||||
!ERROR: Only the TO, FROM, TOFROM, ALLOC map types are permitted for MAP clauses on the TARGET TEAMS DISTRIBUTE PARALLEL DO directive
|
||||
!ERROR: Only the ALLOC, FROM, TO, TOFROM map types are permitted for MAP clauses on the TARGET TEAMS DISTRIBUTE PARALLEL DO directive
|
||||
!$omp target teams distribute parallel do map(delete:a)
|
||||
do i = 1, N
|
||||
a(i) = 3.14
|
||||
@ -500,7 +500,7 @@ program main
|
||||
enddo
|
||||
!$omp end target teams distribute parallel do simd
|
||||
|
||||
!ERROR: Only the TO, FROM, TOFROM, ALLOC map types are permitted for MAP clauses on the TARGET TEAMS DISTRIBUTE PARALLEL DO SIMD directive
|
||||
!ERROR: Only the ALLOC, FROM, TO, TOFROM map types are permitted for MAP clauses on the TARGET TEAMS DISTRIBUTE PARALLEL DO SIMD directive
|
||||
!$omp target teams distribute parallel do simd map(delete:a)
|
||||
do i = 1, N
|
||||
a(i) = 3.14
|
||||
|
@ -123,7 +123,7 @@ program main
|
||||
enddo
|
||||
!$omp end target
|
||||
|
||||
!ERROR: Only the TO, FROM, TOFROM, ALLOC map types are permitted for MAP clauses on the TARGET directive
|
||||
!ERROR: Only the ALLOC, FROM, TO, TOFROM map types are permitted for MAP clauses on the TARGET directive
|
||||
!$omp target map(delete:a)
|
||||
do i = 1, N
|
||||
a = 3.14
|
||||
@ -160,7 +160,7 @@ program main
|
||||
!ERROR: At most one IF clause can appear on the TARGET ENTER DATA directive
|
||||
!$omp target enter data map(to:a) if(.true.) if(.false.)
|
||||
|
||||
!ERROR: Only the TO, ALLOC map types are permitted for MAP clauses on the TARGET ENTER DATA directive
|
||||
!ERROR: Only the ALLOC, TO, TOFROM map types are permitted for MAP clauses on the TARGET ENTER DATA directive
|
||||
!$omp target enter data map(from:a)
|
||||
|
||||
!$omp target exit data map(delete:a)
|
||||
@ -168,7 +168,7 @@ program main
|
||||
!ERROR: At most one DEVICE clause can appear on the TARGET EXIT DATA directive
|
||||
!$omp target exit data map(from:a) device(0) device(1)
|
||||
|
||||
!ERROR: Only the FROM, RELEASE, DELETE map types are permitted for MAP clauses on the TARGET EXIT DATA directive
|
||||
!ERROR: Only the DELETE, FROM, RELEASE, TOFROM map types are permitted for MAP clauses on the TARGET EXIT DATA directive
|
||||
!$omp target exit data map(to:a)
|
||||
|
||||
!$omp target update if(.true.) device(1) to(a) from(b) depend(inout:c) nowait
|
||||
|
35
flang/test/Semantics/OpenMP/map-modifiers-v60.f90
Normal file
35
flang/test/Semantics/OpenMP/map-modifiers-v60.f90
Normal file
@ -0,0 +1,35 @@
|
||||
!RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=52 -Werror
|
||||
|
||||
subroutine f00(x)
|
||||
integer :: x
|
||||
!WARNING: 'self-modifier' modifier is not supported in OpenMP v5.2, try -fopenmp-version=60
|
||||
!$omp target map(self: x)
|
||||
x = x + 1
|
||||
!$omp end target
|
||||
end
|
||||
|
||||
subroutine f01(x)
|
||||
integer, pointer :: x
|
||||
!WARNING: 'ref-modifier' modifier is not supported in OpenMP v5.2, try -fopenmp-version=60
|
||||
!$omp target map(ref_ptr: x)
|
||||
x = x + 1
|
||||
!$omp end target
|
||||
end
|
||||
|
||||
subroutine f02(x)
|
||||
integer, pointer :: x
|
||||
!WARNING: 'ref-modifier' modifier is not supported in OpenMP v5.2, try -fopenmp-version=60
|
||||
!$omp target map(ref_ptee: x)
|
||||
x = x + 1
|
||||
!$omp end target
|
||||
end
|
||||
|
||||
subroutine f03(x)
|
||||
integer, pointer :: x
|
||||
!WARNING: 'ref-modifier' modifier is not supported in OpenMP v5.2, try -fopenmp-version=60
|
||||
!$omp target map(ref_ptr_ptee: x)
|
||||
x = x + 1
|
||||
!$omp end target
|
||||
end
|
||||
|
||||
|
@ -779,16 +779,17 @@ struct LinkT {
|
||||
template <typename T, typename I, typename E> //
|
||||
struct MapT {
|
||||
using LocatorList = ObjectListT<I, E>;
|
||||
ENUM(MapType, To, From, Tofrom, Alloc, Release, Delete);
|
||||
ENUM(MapTypeModifier, Always, Close, Present, OmpxHold);
|
||||
ENUM(MapType, To, From, Tofrom, Storage);
|
||||
ENUM(MapTypeModifier, Always, Close, Delete, Present, Self, OmpxHold);
|
||||
ENUM(RefModifier, RefPtee, RefPtr, RefPtrPtee);
|
||||
// See note at the definition of the MapperT type.
|
||||
using Mappers = ListT<type::MapperT<I, E>>; // Not a spec name
|
||||
using Iterator = type::IteratorT<T, I, E>;
|
||||
using MapTypeModifiers = ListT<MapTypeModifier>; // Not a spec name
|
||||
|
||||
using TupleTrait = std::true_type;
|
||||
std::tuple<OPT(MapType), OPT(MapTypeModifiers), OPT(Mappers), OPT(Iterator),
|
||||
LocatorList>
|
||||
std::tuple<OPT(MapType), OPT(MapTypeModifiers), OPT(RefModifier),
|
||||
OPT(Mappers), OPT(Iterator), LocatorList>
|
||||
t;
|
||||
};
|
||||
|
||||
|
@ -708,6 +708,7 @@ bool ConstructDecompositionT<C, H>::applyClause(
|
||||
tomp::clause::MapT<TypeTy, IdTy, ExprTy>{
|
||||
{/*MapType=*/MapType::Tofrom,
|
||||
/*MapTypeModifier=*/std::nullopt,
|
||||
/*RefModifier=*/std::nullopt,
|
||||
/*Mapper=*/std::nullopt, /*Iterator=*/std::nullopt,
|
||||
/*LocatorList=*/std::move(tofrom)}});
|
||||
dirTarget->clauses.push_back(map);
|
||||
@ -969,8 +970,8 @@ bool ConstructDecompositionT<C, H>::applyClause(
|
||||
llvm::omp::Clause::OMPC_map,
|
||||
tomp::clause::MapT<TypeTy, IdTy, ExprTy>{
|
||||
{/*MapType=*/MapType::Tofrom, /*MapTypeModifier=*/std::nullopt,
|
||||
/*Mapper=*/std::nullopt, /*Iterator=*/std::nullopt,
|
||||
/*LocatorList=*/std::move(tofrom)}});
|
||||
/*RefModifier=*/std::nullopt, /*Mapper=*/std::nullopt,
|
||||
/*Iterator=*/std::nullopt, /*LocatorList=*/std::move(tofrom)}});
|
||||
|
||||
dirTarget->clauses.push_back(map);
|
||||
applied = true;
|
||||
|
@ -431,8 +431,8 @@ TEST_F(OpenMPDecompositionTest, Firstprivate3) {
|
||||
std::string Dir0 = stringify(Dec.output[0]);
|
||||
std::string Dir1 = stringify(Dec.output[1]);
|
||||
std::string Dir2 = stringify(Dec.output[2]);
|
||||
ASSERT_EQ(Dir0, "target map(2, , , , (x))"); // (12), (27)
|
||||
ASSERT_EQ(Dir1, "teams shared(x)"); // (6), (17)
|
||||
ASSERT_EQ(Dir0, "target map(2, , , , , (x))"); // (12), (27)
|
||||
ASSERT_EQ(Dir1, "teams shared(x)"); // (6), (17)
|
||||
ASSERT_EQ(Dir2, "distribute firstprivate(x) lastprivate(, (x))"); // (5), (21)
|
||||
}
|
||||
|
||||
@ -574,9 +574,9 @@ TEST_F(OpenMPDecompositionTest, Lastprivate3) {
|
||||
std::string Dir0 = stringify(Dec.output[0]);
|
||||
std::string Dir1 = stringify(Dec.output[1]);
|
||||
std::string Dir2 = stringify(Dec.output[2]);
|
||||
ASSERT_EQ(Dir0, "target map(2, , , , (x))"); // (21), (27)
|
||||
ASSERT_EQ(Dir1, "parallel shared(x)"); // (22)
|
||||
ASSERT_EQ(Dir2, "do lastprivate(, (x))"); // (21)
|
||||
ASSERT_EQ(Dir0, "target map(2, , , , , (x))"); // (21), (27)
|
||||
ASSERT_EQ(Dir1, "parallel shared(x)"); // (22)
|
||||
ASSERT_EQ(Dir2, "do lastprivate(, (x))"); // (21)
|
||||
}
|
||||
|
||||
// SHARED
|
||||
@ -984,9 +984,9 @@ TEST_F(OpenMPDecompositionTest, Reduction7) {
|
||||
std::string Dir0 = stringify(Dec.output[0]);
|
||||
std::string Dir1 = stringify(Dec.output[1]);
|
||||
std::string Dir2 = stringify(Dec.output[2]);
|
||||
ASSERT_EQ(Dir0, "target map(2, , , , (x))"); // (36), (10)
|
||||
ASSERT_EQ(Dir1, "parallel shared(x)"); // (36), (1), (4)
|
||||
ASSERT_EQ(Dir2, "do reduction(, (3), (x))"); // (36)
|
||||
ASSERT_EQ(Dir0, "target map(2, , , , , (x))"); // (36), (10)
|
||||
ASSERT_EQ(Dir1, "parallel shared(x)"); // (36), (1), (4)
|
||||
ASSERT_EQ(Dir2, "do reduction(, (3), (x))"); // (36)
|
||||
}
|
||||
|
||||
// IF
|
||||
|
Loading…
x
Reference in New Issue
Block a user