Skip to content

[flang][OpenMP] Sema checks, lowering with new format of MAP modifiers #149137

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Jul 22, 2025
Merged
Show file tree
Hide file tree
Changes from all 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
5 changes: 2 additions & 3 deletions flang/include/flang/Semantics/symbol.h
Original file line number Diff line number Diff line change
Expand Up @@ -812,9 +812,8 @@ class Symbol {
// 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
Expand Down
16 changes: 8 additions & 8 deletions flang/lib/Lower/OpenMP/ClauseProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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) {
Expand All @@ -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;
}
Expand Down
95 changes: 65 additions & 30 deletions flang/lib/Lower/OpenMP/Clauses.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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 mappers = [&]() -> std::optional<List<Mapper>> {
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 List<Mapper>{Mapper{makeObject(t1->v, semaCtx)}};
return convertMapType(t1->v);
return std::nullopt;
}();

auto iterator = [&]() -> std::optional<Iterator> {
if (t2)
return makeIterator(*t2, semaCtx);
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 type = [&]() -> std::optional<Map::MapType> {
if (t3)
return convert1(t3->v);
auto mappers = [&]() -> std::optional<List<Mapper>> {
if (auto *t = semantics::OmpGetUniqueModifier<parser::OmpMapper>(mods))
return List<Mapper>{Mapper{makeObject(t->v, semaCtx)}};
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);
auto iterator = [&]() -> std::optional<Iterator> {
if (auto *t = semantics::OmpGetUniqueModifier<parser::OmpIterator>(mods))
return makeIterator(*t, semaCtx);
return std::nullopt;
}();

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,
Expand Down
15 changes: 11 additions & 4 deletions flang/lib/Semantics/canonicalize-omp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()} {}
Comment on lines +30 to +31
Copy link
Member

@Meinersbur Meinersbur Jul 23, 2025

Choose a reason for hiding this comment

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

This adds a use of SemanticContext without including its header file. This means the build was failing when precompiled headers are disabled.

See https://lab.llvm.org/staging/#/builders/36/builds/21866

Fixed in 0586067


void Post(parser::Block &block) {
for (auto it{block.begin()}; it != block.end(); ++it) {
Expand Down Expand Up @@ -401,6 +402,11 @@ class CanonicalizationOfOmp {
// 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;
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we warn about the new map modifiers being used with older versions?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The OmpValidateModifiiers function should be doing that. I can add a testcase for that.

}

// Omp{Always, Close, Present, xHold}Modifier -> OmpMapTypeModifier
// OmpDeleteModifier -> OmpMapType
using Modifier = parser::OmpMapClause::Modifier;
Expand Down Expand Up @@ -432,12 +438,13 @@ class CanonicalizationOfOmp {
// 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
5 changes: 2 additions & 3 deletions flang/lib/Semantics/canonicalize-omp.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_
107 changes: 71 additions & 36 deletions flang/lib/Semantics/check-omp-structure.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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) {
Expand All @@ -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);
}
}

Expand Down
4 changes: 2 additions & 2 deletions flang/lib/Semantics/check-omp-structure.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,8 @@ class OmpStructureChecker
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 &);
Expand Down
Loading
Loading