Skip to content
Merged
7 changes: 7 additions & 0 deletions flang/include/flang/Lower/OpenMP.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,13 @@ bool markOpenMPDeferredDeclareTargetFunctions(
AbstractConverter &);
void genOpenMPRequires(mlir::Operation *, const Fortran::semantics::Symbol *);

// Materialize omp.declare_mapper ops for mapper declarations found in
// imported modules. If \p scope is null, materialize for the whole
// semantics global scope; otherwise, operate recursively starting at \p scope.
void materializeOpenMPDeclareMappers(
Fortran::lower::AbstractConverter &, Fortran::semantics::SemanticsContext &,
const Fortran::semantics::Scope *scope = nullptr);

} // namespace lower
} // namespace Fortran

Expand Down
20 changes: 19 additions & 1 deletion flang/include/flang/Semantics/symbol.h
Original file line number Diff line number Diff line change
Expand Up @@ -777,14 +777,32 @@ class UserReductionDetails {
DeclVector declList_;
};

// Used for OpenMP DECLARE MAPPER, it holds the declaration constructs
// so they can be serialized into module files and later re-parsed when
// USE-associated.
class MapperDetails {
public:
using DeclVector = std::vector<const parser::OpenMPDeclarativeConstruct *>;

MapperDetails() = default;

void AddDecl(const parser::OpenMPDeclarativeConstruct *decl) {
declList_.emplace_back(decl);
}
const DeclVector &GetDeclList() const { return declList_; }

private:
DeclVector declList_;
};

class UnknownDetails {};

using Details = std::variant<UnknownDetails, MainProgramDetails, ModuleDetails,
SubprogramDetails, SubprogramNameDetails, EntityDetails,
ObjectEntityDetails, ProcEntityDetails, AssocEntityDetails,
DerivedTypeDetails, UseDetails, UseErrorDetails, HostAssocDetails,
GenericDetails, ProcBindingDetails, NamelistDetails, CommonBlockDetails,
TypeParamDetails, MiscDetails, UserReductionDetails>;
TypeParamDetails, MiscDetails, UserReductionDetails, MapperDetails>;
llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Details &);
std::string DetailsToString(const Details &);

Expand Down
7 changes: 7 additions & 0 deletions flang/lib/Lower/Bridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,13 @@ class FirConverter : public Fortran::lower::AbstractConverter {
}
});

// Ensure imported OpenMP declare mappers are materialized at module
// scope before lowering any constructs that may reference them.
createBuilderOutsideOfFuncOpAndDo([&]() {
Fortran::lower::materializeOpenMPDeclareMappers(
*this, bridge.getSemanticsContext());
});

// Create definitions of intrinsic module constants.
createBuilderOutsideOfFuncOpAndDo(
[&]() { createIntrinsicModuleDefinitions(pft); });
Expand Down
12 changes: 8 additions & 4 deletions flang/lib/Lower/OpenMP/ClauseProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1392,10 +1392,14 @@ bool ClauseProcessor::processMap(
}
if (mappers) {
assert(mappers->size() == 1 && "more than one mapper");
mapperIdName = mappers->front().v.id().symbol->name().ToString();
if (mapperIdName != "default")
mapperIdName = converter.mangleName(
mapperIdName, mappers->front().v.id().symbol->owner());
const semantics::Symbol *mapperSym = mappers->front().v.id().symbol;
mapperIdName = mapperSym->name().ToString();
if (mapperIdName != "default") {
// Mangle with the ultimate owner so that use-associated mapper
// identifiers resolve to the same symbol as their defining scope.
const semantics::Symbol &ultimate = mapperSym->GetUltimate();
mapperIdName = converter.mangleName(mapperIdName, ultimate.owner());
}
}

processMapObjects(stmtCtx, clauseLocation,
Expand Down
59 changes: 54 additions & 5 deletions flang/lib/Lower/OpenMP/OpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3543,10 +3543,10 @@ genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
TODO(converter.getCurrentLocation(), "OpenMPDeclareSimdConstruct");
}

static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
semantics::SemanticsContext &semaCtx,
lower::pft::Evaluation &eval,
const parser::OpenMPDeclareMapperConstruct &construct) {
static void genOpenMPDeclareMapperImpl(
lower::AbstractConverter &converter, semantics::SemanticsContext &semaCtx,
const parser::OpenMPDeclareMapperConstruct &construct,
const semantics::Symbol *mapperSymOpt = nullptr) {
mlir::Location loc = converter.genLocation(construct.source);
fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
const parser::OmpArgumentList &args = construct.v.Arguments();
Expand All @@ -3562,8 +3562,17 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
"Expected derived type");

std::string mapperNameStr = mapperName;
if (auto *sym = converter.getCurrentScope().FindSymbol(mapperNameStr))
if (mapperSymOpt && mapperNameStr != "default") {
mapperNameStr = converter.mangleName(mapperNameStr, mapperSymOpt->owner());
} else if (auto *sym =
converter.getCurrentScope().FindSymbol(mapperNameStr)) {
mapperNameStr = converter.mangleName(mapperNameStr, sym->owner());
}

// If the mapper op already exists (e.g., created by regular lowering or by
// materialization of imported mappers), do not recreate it.
if (converter.getModuleOp().lookupSymbol(mapperNameStr))
return;

// Save current insertion point before moving to the module scope to create
// the DeclareMapperOp
Expand All @@ -3586,6 +3595,13 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
mlir::omp::DeclareMapperInfoOp::create(firOpBuilder, loc, clauseOps.mapVars);
}

static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
semantics::SemanticsContext &semaCtx,
lower::pft::Evaluation &eval,
const parser::OpenMPDeclareMapperConstruct &construct) {
genOpenMPDeclareMapperImpl(converter, semaCtx, construct);
}

static void
genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
semantics::SemanticsContext &semaCtx, lower::pft::Evaluation &eval,
Expand Down Expand Up @@ -4229,3 +4245,36 @@ void Fortran::lower::genOpenMPRequires(mlir::Operation *mod,
offloadMod.setRequires(mlirFlags);
}
}

// Walk scopes and materialize omp.declare_mapper ops for mapper declarations
// found in imported modules. If \p scope is null, start from the global scope.
void Fortran::lower::materializeOpenMPDeclareMappers(
Fortran::lower::AbstractConverter &converter,
semantics::SemanticsContext &semaCtx, const semantics::Scope *scope) {
const semantics::Scope &root = scope ? *scope : semaCtx.globalScope();

// Recurse into child scopes first (modules, submodules, etc.).
for (const semantics::Scope &child : root.children())
materializeOpenMPDeclareMappers(converter, semaCtx, &child);

// Only consider module scopes to avoid duplicating local constructs.
if (!root.IsModule())
return;

// Only materialize for modules coming from mod files to avoid duplicates.
if (!root.symbol() || !root.symbol()->test(semantics::Symbol::Flag::ModFile))
return;

// Scan symbols in this module scope for MapperDetails.
for (auto &it : root) {
const semantics::Symbol &sym = *it.second;
if (auto *md = sym.detailsIf<semantics::MapperDetails>()) {
for (const auto *decl : md->GetDeclList()) {
if (const auto *mapperDecl =
std::get_if<parser::OpenMPDeclareMapperConstruct>(&decl->u)) {
genOpenMPDeclareMapperImpl(converter, semaCtx, *mapperDecl, &sym);
}
}
}
}
}
12 changes: 12 additions & 0 deletions flang/lib/Semantics/mod-file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ static void PutBound(llvm::raw_ostream &, const Bound &);
static void PutShapeSpec(llvm::raw_ostream &, const ShapeSpec &);
static void PutShape(
llvm::raw_ostream &, const ArraySpec &, char open, char close);
static void PutMapper(llvm::raw_ostream &, const Symbol &, SemanticsContext &);

static llvm::raw_ostream &PutAttr(llvm::raw_ostream &, Attr);
static llvm::raw_ostream &PutType(llvm::raw_ostream &, const DeclTypeSpec &);
Expand Down Expand Up @@ -938,6 +939,7 @@ void ModFileWriter::PutEntity(llvm::raw_ostream &os, const Symbol &symbol) {
[&](const ProcEntityDetails &) { PutProcEntity(os, symbol); },
[&](const TypeParamDetails &) { PutTypeParam(os, symbol); },
[&](const UserReductionDetails &) { PutUserReduction(os, symbol); },
[&](const MapperDetails &) { PutMapper(decls_, symbol, context_); },
[&](const auto &) {
common::die("PutEntity: unexpected details: %s",
DetailsToString(symbol.details()).c_str());
Expand Down Expand Up @@ -1101,6 +1103,16 @@ void ModFileWriter::PutUserReduction(
}
}

static void PutMapper(
llvm::raw_ostream &os, const Symbol &symbol, SemanticsContext &context) {
const auto &details{symbol.get<MapperDetails>()};
// Emit each saved DECLARE MAPPER construct as-is, so that consumers of the
// module can reparse it and recreate the mapper symbol and semantics state.
for (const auto *decl : details.GetDeclList()) {
Unparse(os, *decl, context.langOptions());
}
}

void PutInit(llvm::raw_ostream &os, const Symbol &symbol, const MaybeExpr &init,
const parser::Expr *unanalyzed, SemanticsContext &context) {
if (IsNamedConstant(symbol) || symbol.owner().IsDerivedType()) {
Expand Down
47 changes: 34 additions & 13 deletions flang/lib/Semantics/resolve-names.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1852,21 +1852,25 @@ bool OmpVisitor::Pre(const parser::OmpMapClause &x) {
// TODO: Do we need a specific flag or type here, to distinghuish against
// other ConstructName things? Leaving this for the full implementation
// of mapper lowering.
auto *misc{symbol->detailsIf<MiscDetails>()};
if (!misc || misc->kind() != MiscDetails::Kind::ConstructName)
auto &ultimate{symbol->GetUltimate()};
auto *misc{ultimate.detailsIf<MiscDetails>()};
auto *md{ultimate.detailsIf<MapperDetails>()};
if (!md && (!misc || misc->kind() != MiscDetails::Kind::ConstructName))
context().Say(mapper->v.source,
"Name '%s' should be a mapper name"_err_en_US, mapper->v.source);
else
mapper->v.symbol = symbol;
} else {
mapper->v.symbol =
&MakeSymbol(mapper->v, MiscDetails{MiscDetails::Kind::ConstructName});
// TODO: When completing the implementation, we probably want to error if
// the symbol is not declared, but right now, testing that the TODO for
// OmpMapClause happens is obscured by the TODO for declare mapper, so
// leaving this out. Remove the above line once the declare mapper is
// implemented. context().Say(mapper->v.source, "'%s' not
// declared"_err_en_US, mapper->v.source);
// Allow the special 'default' mapper identifier without prior
// declaration so lowering can recognize and handle it. Emit an
// error for any other missing mapper identifier.
if (mapper->v.source.ToString() == "default") {
mapper->v.symbol = &MakeSymbol(
mapper->v, MiscDetails{MiscDetails::Kind::ConstructName});
} else {
context().Say(
mapper->v.source, "'%s' not declared"_err_en_US, mapper->v.source);
}
}
}
return true;
Expand All @@ -1880,8 +1884,15 @@ void OmpVisitor::ProcessMapperSpecifier(const parser::OmpMapperSpecifier &spec,
// the type has been fully processed.
BeginDeclTypeSpec();
auto &mapperName{std::get<std::string>(spec.t)};
MakeSymbol(parser::CharBlock(mapperName), Attrs{},
MiscDetails{MiscDetails::Kind::ConstructName});
// Create or update the mapper symbol with MapperDetails and
// keep track of the declarative construct for module emission.
Symbol &mapperSym{MakeSymbol(parser::CharBlock(mapperName), Attrs{})};
if (auto *md{mapperSym.detailsIf<MapperDetails>()}) {
md->AddDecl(declaratives_.back());
} else if (mapperSym.has<UnknownDetails>() || mapperSym.has<MiscDetails>()) {
mapperSym.set_details(MapperDetails{});
mapperSym.get<MapperDetails>().AddDecl(declaratives_.back());
}
PushScope(Scope::Kind::OtherConstruct, nullptr);
Walk(std::get<parser::TypeSpec>(spec.t));
auto &varName{std::get<parser::Name>(spec.t)};
Expand Down Expand Up @@ -3611,10 +3622,20 @@ void ModuleVisitor::Post(const parser::UseStmt &x) {
rename.u);
}
for (const auto &[name, symbol] : *useModuleScope_) {
// Default USE imports public names, excluding intrinsic-only and most
// miscellaneous details. Allow OpenMP mapper identifiers represented
// as MapperDetails, and also legacy MiscDetails::ConstructName.
bool isMapper{symbol->has<MapperDetails>()};
if (!isMapper) {
if (const auto *misc{symbol->detailsIf<MiscDetails>()}) {
isMapper = misc->kind() == MiscDetails::Kind::ConstructName;
}
}
if (symbol->attrs().test(Attr::PUBLIC) && !IsUseRenamed(symbol->name()) &&
(!symbol->implicitAttrs().test(Attr::INTRINSIC) ||
symbol->has<UseDetails>()) &&
!symbol->has<MiscDetails>() && useNames.count(name) == 0) {
(!symbol->has<MiscDetails>() || isMapper) &&
useNames.count(name) == 0) {
SourceName location{x.moduleName.source};
if (auto *localSymbol{FindInScope(name)}) {
DoAddUse(location, localSymbol->name(), *localSymbol, *symbol);
Expand Down
6 changes: 5 additions & 1 deletion flang/lib/Semantics/symbol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,8 @@ std::string DetailsToString(const Details &details) {
[](const TypeParamDetails &) { return "TypeParam"; },
[](const MiscDetails &) { return "Misc"; },
[](const AssocEntityDetails &) { return "AssocEntity"; },
[](const UserReductionDetails &) { return "UserReductionDetails"; }},
[](const UserReductionDetails &) { return "UserReductionDetails"; },
[](const MapperDetails &) { return "MapperDetails"; }},
details);
}

Expand Down Expand Up @@ -379,6 +380,7 @@ bool Symbol::CanReplaceDetails(const Details &details) const {
[&](const UserReductionDetails &) {
return has<UserReductionDetails>();
},
[&](const MapperDetails &) { return has<MapperDetails>(); },
[](const auto &) { return false; },
},
details);
Expand Down Expand Up @@ -685,6 +687,8 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Details &details) {
DumpType(os, type);
}
},
// Avoid recursive streaming for MapperDetails; nothing more to dump
[&](const MapperDetails &) {},
[&](const auto &x) { os << x; },
},
details);
Expand Down
26 changes: 25 additions & 1 deletion flang/test/Lower/OpenMP/declare-mapper.f90
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %t/omp-declare-mapper-3.f90 -o - | FileCheck %t/omp-declare-mapper-3.f90
! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %t/omp-declare-mapper-4.f90 -o - | FileCheck %t/omp-declare-mapper-4.f90
! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %t/omp-declare-mapper-5.f90 -o - | FileCheck %t/omp-declare-mapper-5.f90
! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=51 %t/omp-declare-mapper-6.f90 -o - | FileCheck %t/omp-declare-mapper-6.f90
! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %t/omp-declare-mapper-6.f90 -o - | FileCheck %t/omp-declare-mapper-6.f90
! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 -module-dir %t %t/omp-declare-mapper-7.mod.f90 -o - >/dev/null
! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 -J %t %t/omp-declare-mapper-7.use.f90 -o - | FileCheck %t/omp-declare-mapper-7.use.f90

!--- omp-declare-mapper-1.f90
subroutine declare_mapper_1
Expand Down Expand Up @@ -301,3 +303,25 @@ subroutine declare_mapper_nested_parent
r%real_arr = r%base_arr(1) + r%inner%deep_arr(1)
!$omp end target
end subroutine declare_mapper_nested_parent

!--- omp-declare-mapper-7.mod.f90
! Module with DECLARE MAPPER to be compiled separately
module m_mod
implicit none
type :: mty
integer :: x
end type mty
!$omp declare mapper(mymap : mty :: v) map(tofrom: v%x)
end module m_mod

!--- omp-declare-mapper-7.use.f90
! Consumer program that USEs the module and applies the mapper by name.
! CHECK: %{{.*}} = omp.map.info {{.*}} mapper(@{{.*mymap}}) {{.*}} {name = "a"}
program use_module_mapper
use m_mod
implicit none
type(mty) :: a
!$omp target map(mapper(mymap) : a)
a%x = 42
!$omp end target
end program use_module_mapper
7 changes: 3 additions & 4 deletions flang/test/Parser/OpenMP/map-modifiers.f90
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ subroutine f21(x, y)
integer :: x(10)
integer :: y
integer, parameter :: p = 23
!$omp target map(mapper(xx), from: x)
!$omp target map(mapper(default), from: x)
x = x + 1
!$omp end target
end
Expand All @@ -329,15 +329,15 @@ subroutine f21(x, y)
!UNPARSE: INTEGER x(10_4)
!UNPARSE: INTEGER y
!UNPARSE: INTEGER, PARAMETER :: p = 23_4
!UNPARSE: !$OMP TARGET MAP(MAPPER(XX), FROM: X)
!UNPARSE: !$OMP TARGET MAP(MAPPER(DEFAULT), FROM: X)
!UNPARSE: x=x+1_4
!UNPARSE: !$OMP END TARGET
!UNPARSE: END SUBROUTINE

!PARSE-TREE: OmpBeginDirective
!PARSE-TREE: | OmpDirectiveName -> llvm::omp::Directive = target
!PARSE-TREE: | OmpClauseList -> OmpClause -> Map -> OmpMapClause
!PARSE-TREE: | | Modifier -> OmpMapper -> Name = 'xx'
!PARSE-TREE: | | Modifier -> OmpMapper -> Name = 'default'
!PARSE-TREE: | | Modifier -> OmpMapType -> Value = From
!PARSE-TREE: | | OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'

Expand Down Expand Up @@ -375,4 +375,3 @@ subroutine f22(x)
!PARSE-TREE: | | SectionSubscript -> Integer -> Expr = 'i'
!PARSE-TREE: | | | Designator -> DataRef -> Name = 'i'
!PARSE-TREE: | bool = 'true'

14 changes: 14 additions & 0 deletions flang/test/Semantics/OpenMP/declare-mapper-modfile.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
! RUN: split-file %s %t
! RUN: %flang_fc1 -fsyntax-only -fopenmp -fopenmp-version=50 -module-dir %t %t/m.f90
! RUN: cat %t/m.mod | FileCheck --ignore-case %s

!--- m.f90
module m
implicit none
type :: t
integer :: x
end type t
!$omp declare mapper(mymap : t :: v) map(v%x)
end module m

!CHECK: !$OMP DECLARE MAPPER(mymap:t::v) MAP(v%x)
Loading
Loading