https://github.com/chichunchen updated https://github.com/llvm/llvm-project/pull/197752
>From afa1a62e201c6674ba352e0348e13dce6063aa2c Mon Sep 17 00:00:00 2001 From: "Chi Chun, Chen" <[email protected]> Date: Tue, 12 May 2026 15:06:58 -0500 Subject: [PATCH 1/2] [flang][OpenMP][NFC] Share declare mapper helpers for iterator modifier lowering Move mapper lookup and implicit default mapper creation into reusable OpenMP lowering helpers so regular map lowering and iterator-generated map entries can use the same resolution path. This prepares Flang iterator modifier lowering for map and motion clauses without changing the generated IR for existing non-iterator maps. --- flang/lib/Lower/OpenMP/ClauseProcessor.cpp | 148 +------------------- flang/lib/Lower/OpenMP/Utils.cpp | 153 +++++++++++++++++++++ flang/lib/Lower/OpenMP/Utils.h | 7 + 3 files changed, 166 insertions(+), 142 deletions(-) diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp index 213b5f783430e..5948e597aa2de 100644 --- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp +++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp @@ -1722,88 +1722,6 @@ void ClauseProcessor::processMapObjects( bool isMotionModifier, llvm::omp::Directive directive) const { fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); - auto getSymbolDerivedType = [](const semantics::Symbol &symbol) - -> const semantics::DerivedTypeSpec * { - const semantics::Symbol &ultimate = symbol.GetUltimate(); - if (const semantics::DeclTypeSpec *declType = ultimate.GetType()) - if (const auto *derived = declType->AsDerived()) - return derived; - return nullptr; - }; - - auto addImplicitMapper = [&](const omp::Object &object, - std::string &mapperIdName, - bool allowGenerate) -> mlir::FlatSymbolRefAttr { - if (!allowGenerate || mapperIdName.empty()) - return mlir::FlatSymbolRefAttr(); - - const semantics::DerivedTypeSpec *typeSpec = - getSymbolDerivedType(*object.sym()); - if (!typeSpec && object.sym()->owner().IsDerivedType()) - typeSpec = object.sym()->owner().derivedTypeSpec(); - - if (!typeSpec) - return mlir::FlatSymbolRefAttr(); - - mlir::Type type = converter.genType(*typeSpec); - auto recordType = mlir::dyn_cast<fir::RecordType>(type); - if (!recordType) - return mlir::FlatSymbolRefAttr(); - - return utils::openmp::getOrGenImplicitDefaultDeclareMapper( - converter.getFirOpBuilder(), clauseLocation, recordType, mapperIdName, - [&](std::string &mapperIdName, llvm::StringRef memberName) { - defaultMangler(converter, mapperIdName, memberName); - }); - }; - - auto getDefaultMapperID = - [&](const semantics::DerivedTypeSpec *typeSpec) -> std::string { - if (mlir::isa<mlir::omp::DeclareMapperOp>( - firOpBuilder.getRegion().getParentOp()) || - !typeSpec) - return {}; - - std::string mapperIdName = - typeSpec->name().ToString() + llvm::omp::OmpDefaultMapperName; - if (auto *sym = converter.getCurrentScope().FindSymbol(mapperIdName)) { - mapperIdName = - converter.mangleName(mapperIdName, sym->GetUltimate().owner()); - } else { - mapperIdName = converter.mangleName(mapperIdName, *typeSpec->GetScope()); - } - - // Make sure we don't return a mapper to self. - if (auto declMapOp = mlir::dyn_cast<mlir::omp::DeclareMapperOp>( - firOpBuilder.getRegion().getParentOp())) - if (mapperIdName == declMapOp.getSymName()) - return {}; - return mapperIdName; - }; - - auto findMapperIfTypeMatch = - [&](const semantics::DerivedTypeSpec *objectTypeSpec, - llvm::StringRef explicitMapperName) -> std::string { - auto declMapperOp = - converter.getModuleOp().lookupSymbol<mlir::omp::DeclareMapperOp>( - explicitMapperName); - if (!declMapperOp) - return "__implicit_mapper"; - - // Verify if the explicit mapper provided matches the type being mapped. - // If it does return the mapper name, if it doesn't return null-ary. - mlir::Type mapperType = declMapperOp.getType(); - mlir::Type objectType = converter.genType(*objectTypeSpec); - auto mapperRecordType = mlir::dyn_cast<fir::RecordType>(mapperType); - auto objectRecordType = mlir::dyn_cast<fir::RecordType>(objectType); - if (mapperRecordType && objectRecordType && - mapperRecordType.getName() == objectRecordType.getName()) { - return explicitMapperName.str(); - } - - return "__implicit_mapper"; - }; - for (const omp::Object &object : objects) { llvm::SmallVector<mlir::Value> bounds; std::stringstream asFortran; @@ -1835,62 +1753,9 @@ void ClauseProcessor::processMapObjects( } } - const semantics::DerivedTypeSpec *objectTypeSpec = - getSymbolDerivedType(*object.sym()); - mlir::FlatSymbolRefAttr mapperId = mlir::FlatSymbolRefAttr(); - if (objectTypeSpec) { - std::string mapperIdName = mapperIdNameRef.str(); - // if we have an explicit mapper specified, we need to check it matches - // the type being mapped, if it doesn't we fallback to look for a user - // default mapper or generate an compiler defined default mapper if - // relevant. This function will return "__implicit_mapper" if we find that - // the map isn't relevant to the explicit declare mapper, which allows it - // to fallback. - if (!mapperIdName.empty() && mapperIdName != "__implicit_mapper") - mapperIdName = findMapperIfTypeMatch(objectTypeSpec, mapperIdName); - - if (mapperIdName == "__implicit_mapper") { - mapperIdName = getDefaultMapperID(objectTypeSpec); - // Currently we do not apply implicit compiler generated delcare mappers - // to enter, exit or update directives. However, we will syntheize one - // below if we're not a target enter/exit/update and no user defined - // implicit declare mapper has been defined and we meet the other - // conditions - // TODO/FIXME: Loosen this restriction to comply with the OpenMP - // specification. - auto *userDefinedDefault = - converter.getModuleOp().lookupSymbol(mapperIdName); - if (!userDefinedDefault && !parentObj.has_value() && - (directive != llvm::omp::Directive::OMPD_target_enter_data && - directive != llvm::omp::Directive::OMPD_target_exit_data && - directive != llvm::omp::Directive::OMPD_target_update)) { - bool isAllocOrPointer = - semantics::IsAllocatableOrObjectPointer(object.sym()); - bool isPointer = semantics::IsPointer(*object.sym()); - bool isImplicitMap = - (mapTypeBits & mlir::omp::ClauseMapFlags::implicit) == - mlir::omp::ClauseMapFlags::implicit; - bool needsDefaultMapper = - isAllocOrPointer || - requiresImplicitDefaultDeclareMapper(*objectTypeSpec); - // For implicit captures, avoid synthesizing default mappers for - // pointer entities (which can over-map pointer payloads) and for - // plain non-allocatable/non-pointer entities. Keep implicit mapper - // support for allocatables. - if (isImplicitMap && (isPointer || !isAllocOrPointer)) - needsDefaultMapper = false; - mapperId = addImplicitMapper(object, mapperIdName, - /*allowGenerate=*/needsDefaultMapper); - } - } - - // Make sure we've generated the symbol in one of our previous steps - // before assigning the symbol. - if (!mapperIdName.empty() && - converter.getModuleOp().lookupSymbol(mapperIdName)) - mapperId = mlir::FlatSymbolRefAttr::get(&converter.getMLIRContext(), - mapperIdName); - } + mlir::FlatSymbolRefAttr mapperId = + resolveMapperId(converter, clauseLocation, object, mapperIdNameRef, + mapTypeBits, directive, parentObj.has_value()); // Explicit map captures are captured ByRef by default, // optimisation passes may alter this to ByCopy or other capture @@ -2034,10 +1899,10 @@ bool ClauseProcessor::processMap( } } - if (iterator) { + if (iterator) TODO(currentLocation, "Support for iterator modifiers is not implemented yet"); - } + processMapObjects(stmtCtx, clauseLocation, std::get<omp::ObjectList>(clause.t), mapTypeBits, parentMemberIndices, result.mapVars, *ptrMapObjects, @@ -2070,9 +1935,8 @@ bool ClauseProcessor::processMotionClauses(lower::StatementContext &stmtCtx, // Support motion modifiers: iterator. std::string mapperIdName = getMapperIdentifier(converter, mapper); - if (iterator) { + if (iterator) TODO(clauseLocation, "Iterator modifier is not supported yet"); - } processMapObjects(stmtCtx, clauseLocation, objects, mapTypeBits, parentMemberIndices, result.mapVars, mapObjects, diff --git a/flang/lib/Lower/OpenMP/Utils.cpp b/flang/lib/Lower/OpenMP/Utils.cpp index fff06bc51e3d6..9ff462f402759 100644 --- a/flang/lib/Lower/OpenMP/Utils.cpp +++ b/flang/lib/Lower/OpenMP/Utils.cpp @@ -1017,6 +1017,159 @@ void defaultMangler(Fortran::lower::AbstractConverter &converter, mapperIdName = converter.mangleName(mapperIdName, memberSym->owner()); } +static const semantics::DerivedTypeSpec * +getSymbolDerivedType(const semantics::Symbol &symbol) { + const semantics::Symbol &ultimate = symbol.GetUltimate(); + if (const semantics::DeclTypeSpec *declType = ultimate.GetType()) + if (const auto *derived = declType->AsDerived()) + return derived; + return nullptr; +} + +static std::string +getDefaultMapperID(Fortran::lower::AbstractConverter &converter, + fir::FirOpBuilder &firOpBuilder, + const semantics::DerivedTypeSpec *typeSpec) { + if (mlir::isa<mlir::omp::DeclareMapperOp>( + firOpBuilder.getRegion().getParentOp()) || + !typeSpec) + return {}; + + std::string mapperIdName = + typeSpec->name().ToString() + llvm::omp::OmpDefaultMapperName; + if (auto *sym = converter.getCurrentScope().FindSymbol(mapperIdName)) { + mapperIdName = + converter.mangleName(mapperIdName, sym->GetUltimate().owner()); + } else { + mapperIdName = converter.mangleName(mapperIdName, *typeSpec->GetScope()); + } + + // Make sure we don't return a mapper to self. + if (auto declMapOp = mlir::dyn_cast<mlir::omp::DeclareMapperOp>( + firOpBuilder.getRegion().getParentOp())) + if (mapperIdName == declMapOp.getSymName()) + return {}; + return mapperIdName; +} + +static std::string +findMapperIfTypeMatch(Fortran::lower::AbstractConverter &converter, + const semantics::DerivedTypeSpec *objectTypeSpec, + llvm::StringRef explicitMapperName) { + auto declMapperOp = + converter.getModuleOp().lookupSymbol<mlir::omp::DeclareMapperOp>( + explicitMapperName); + if (!declMapperOp) + return "__implicit_mapper"; + + // Verify if the explicit mapper provided matches the type being mapped. + // If it does return the mapper name, if it doesn't return null-ary. + mlir::Type mapperType = declMapperOp.getType(); + mlir::Type objectType = converter.genType(*objectTypeSpec); + auto mapperRecordType = mlir::dyn_cast<fir::RecordType>(mapperType); + auto objectRecordType = mlir::dyn_cast<fir::RecordType>(objectType); + if (mapperRecordType && objectRecordType && + mapperRecordType.getName() == objectRecordType.getName()) + return explicitMapperName.str(); + + return "__implicit_mapper"; +} + +static mlir::FlatSymbolRefAttr +addImplicitMapper(Fortran::lower::AbstractConverter &converter, + mlir::Location loc, const omp::Object &object, + std::string &mapperIdName, bool allowGenerate) { + if (!allowGenerate || mapperIdName.empty()) + return mlir::FlatSymbolRefAttr(); + + const semantics::DerivedTypeSpec *typeSpec = + getSymbolDerivedType(*object.sym()); + if (!typeSpec && object.sym()->owner().IsDerivedType()) + typeSpec = object.sym()->owner().derivedTypeSpec(); + + if (!typeSpec) + return mlir::FlatSymbolRefAttr(); + + mlir::Type type = converter.genType(*typeSpec); + auto recordType = mlir::dyn_cast<fir::RecordType>(type); + if (!recordType) + return mlir::FlatSymbolRefAttr(); + + return utils::openmp::getOrGenImplicitDefaultDeclareMapper( + converter.getFirOpBuilder(), loc, recordType, mapperIdName, + [&](std::string &mapperIdName, llvm::StringRef memberName) { + defaultMangler(converter, mapperIdName, memberName); + }); +} + +mlir::FlatSymbolRefAttr +resolveMapperId(Fortran::lower::AbstractConverter &converter, + mlir::Location loc, const omp::Object &object, + llvm::StringRef mapperIdNameRef, + mlir::omp::ClauseMapFlags mapTypeBits, + llvm::omp::Directive directive, bool hasParentObj) { + const semantics::DerivedTypeSpec *objectTypeSpec = + getSymbolDerivedType(*object.sym()); + if (!objectTypeSpec) + return mlir::FlatSymbolRefAttr(); + + fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); + mlir::FlatSymbolRefAttr mapperId; + std::string mapperIdName = mapperIdNameRef.str(); + // if we have an explicit mapper specified, we need to check it matches + // the type being mapped, if it doesn't we fallback to look for a user + // default mapper or generate an compiler defined default mapper if + // relevant. This function will return "__implicit_mapper" if we find that + // the map isn't relevant to the explicit declare mapper, which allows it + // to fallback. + if (!mapperIdName.empty() && mapperIdName != "__implicit_mapper") + mapperIdName = + findMapperIfTypeMatch(converter, objectTypeSpec, mapperIdName); + + if (mapperIdName == "__implicit_mapper") { + mapperIdName = getDefaultMapperID(converter, firOpBuilder, objectTypeSpec); + // Currently we do not apply implicit compiler generated delcare mappers + // to enter, exit or update directives. However, we will syntheize one + // below if we're not a target enter/exit/update and no user defined + // implicit declare mapper has been defined and we meet the other + // conditions + // TODO/FIXME: Loosen this restriction to comply with the OpenMP + // specification. + auto *userDefinedDefault = + converter.getModuleOp().lookupSymbol(mapperIdName); + if (!userDefinedDefault && !hasParentObj && + (directive != llvm::omp::Directive::OMPD_target_enter_data && + directive != llvm::omp::Directive::OMPD_target_exit_data && + directive != llvm::omp::Directive::OMPD_target_update)) { + bool isAllocOrPointer = + semantics::IsAllocatableOrObjectPointer(object.sym()); + bool isPointer = semantics::IsPointer(*object.sym()); + bool isImplicitMap = + (mapTypeBits & mlir::omp::ClauseMapFlags::implicit) == + mlir::omp::ClauseMapFlags::implicit; + bool needsDefaultMapper = + isAllocOrPointer || + requiresImplicitDefaultDeclareMapper(*objectTypeSpec); + // For implicit captures, avoid synthesizing default mappers for + // pointer entities (which can over-map pointer payloads) and for + // plain non-allocatable/non-pointer entities. Keep implicit mapper + // support for allocatables. + if (isImplicitMap && (isPointer || !isAllocOrPointer)) + needsDefaultMapper = false; + mapperId = addImplicitMapper(converter, loc, object, mapperIdName, + /*allowGenerate=*/needsDefaultMapper); + } + } + + // Make sure we've generated the symbol in one of our previous steps + // before assigning the symbol. + if (!mapperIdName.empty() && + converter.getModuleOp().lookupSymbol(mapperIdName)) + mapperId = + mlir::FlatSymbolRefAttr::get(&converter.getMLIRContext(), mapperIdName); + return mapperId; +} + // Build the array coordinate for an object that uses iterator variables. // If the object is a section, use the first element of that section // as the coordinate. Currently only support top-level ArrayRef designators. diff --git a/flang/lib/Lower/OpenMP/Utils.h b/flang/lib/Lower/OpenMP/Utils.h index 7022597a233ca..cee7e187d2d6e 100644 --- a/flang/lib/Lower/OpenMP/Utils.h +++ b/flang/lib/Lower/OpenMP/Utils.h @@ -225,6 +225,13 @@ mlir::Value genIteratorCoordinate(Fortran::lower::AbstractConverter &converter, llvm::ArrayRef<mlir::Value> ivs, mlir::Location loc); +mlir::FlatSymbolRefAttr +resolveMapperId(Fortran::lower::AbstractConverter &converter, + mlir::Location loc, const omp::Object &object, + llvm::StringRef mapperIdName, + mlir::omp::ClauseMapFlags mapTypeBits, + llvm::omp::Directive directive, bool hasParentObj); + std::optional<llvm::SmallVector<mlir::Value>> getIteratorElementIndices( Fortran::lower::AbstractConverter &converter, const omp::Object &object, Fortran::lower::StatementContext &stmtCtx, mlir::Location loc); >From 2c3b35060e4e2096225218545a6b21b9cbbe9dbb Mon Sep 17 00:00:00 2001 From: "Chi Chun, Chen" <[email protected]> Date: Fri, 5 Jun 2026 16:04:22 -0500 Subject: [PATCH 2/2] Add doxygen documentation to resolveMapperId --- flang/lib/Lower/OpenMP/Utils.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/flang/lib/Lower/OpenMP/Utils.h b/flang/lib/Lower/OpenMP/Utils.h index cee7e187d2d6e..59b904526d6ae 100644 --- a/flang/lib/Lower/OpenMP/Utils.h +++ b/flang/lib/Lower/OpenMP/Utils.h @@ -225,6 +225,24 @@ mlir::Value genIteratorCoordinate(Fortran::lower::AbstractConverter &converter, llvm::ArrayRef<mlir::Value> ivs, mlir::Location loc); +/// Resolve the declare mapper symbol to attach to a mapped object. +/// +/// The default mapper path first looks for a user-defined mapper. If none +/// exists, it may synthesize a compiler-generated mapper, except for mapped +/// members whose parent object is also mapped and for target enter data, +/// target exit data, and target update directives. +/// +/// \param converter The converter used to query and generate mapper symbols. +/// \param loc The location to use when generating an implicit mapper. +/// \param object The mapped object whose type controls mapper resolution. +/// \param mapperIdName An explicit mapper name, `__implicit_mapper`, or an +/// empty name. +/// \param mapTypeBits The map flags used when deciding whether an implicit +/// mapper should be generated. +/// \param directive The enclosing OpenMP directive. +/// \param hasParentObj True if a mapped parent object already owns this object. +/// \return A symbol reference to the resolved mapper, or a null attribute when +/// no mapper applies. mlir::FlatSymbolRefAttr resolveMapperId(Fortran::lower::AbstractConverter &converter, mlir::Location loc, const omp::Object &object, _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
