[flang-commits] [flang] [llvm] [Flang][OpenMP][WIP] Initial OpenMP 6.1 Polymorpic Mapping Implementation (PR #228747)
via flang-commits
flang-commits at lists.llvm.org
Sat Oct 3 10:16:39 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-flang-semantics
Author: agozillon
<details>
<summary>Changes</summary>
This PR aims to take an initial step towards supporting polymorphic mapping (class) in Flang OpenMP to target devices. This has predominantly been tested on AMD hardware, namely an MI300A and MI300X.
The PR aims to add:
- Semantic check for versions <= 6.1 that errors out on polymorphic and unlimited polymorphic usage in map clauses and target regions (implicit capture)
- Polymorphic dispatch through declare targeting the relevant RTTI bits to device and then attaching them to the relevant part of the descriptor on device transfer, allowing dispatch through the descriptor on device to trace to the appropriate device function. This seems to work sanely from current testing, but may need some alteration for scenarios that the RTTI ever needs updating on device, this seems unlikely as at least for the moment it's predominantly read-only. The upside is that it saves transfer overhead and maintenance costs for having a non-declare target copy of this RTTI that we transfer over whenever a polymorphic type is encountered in a map, and subsequently any costs for amending/resolving the dispatch tables addresses to resolve to the device variants. I think the main downside is at least for the moment we're forced to declare target ALL the RTTI, which comes with the downside of the usual initial declare target startup costs.
- Ability to use normal polymorphic intrinsics on the polymorphic types, e.g. extends/is, same mechanism as above. Except in this scenario we don't need to declare target the dispatch table just the RTTI.
- Ability to utilise select statements, via same mechanism as above.
- Numerous runtime tests to verify and investigate offload behaviour.
The main mechanism is basically making sure our RTTI which holds the vast majority of polymorphic class state is on the device. In this case opting for declare target as the mechanism to do so as the RTTI remains largely static (in cases it does not, we may have to emit compiler or Fortran runtime level target updates when we trigger these situations occur, I have yet to encounter one and a lot of the RTTI is read-only by nature) and we benefit from not having to wrangle host vs device addressing. So, we declare target the basic RTTI for the class/classes, and we do so for the dispatch table and it's associated functions as well, these then all end up with device side variants. When we map our host side descriptor wrapping our polymorphic class to device, alongside the usual base address pointer attachment we must to a RTTI/derived type pointer attachment, but instead of pointing to a device side copy/clone of the data like we do with the regular base address, we simply point the RTTI/derived type pointer to the device resident declare target RTTI information, so there is no transferal outside of whatever is necessary on runtime startup. Any queries or dispatch access then route through this.
Another lesser detail, is that we have to amend the bounds information for polymorphic classes in certain cases to make use of the dynamic size at the time of mapping, so the object doesn't unintentionally get segmented or otherwise mismapped.
The implementation and legality of all test cases are up for debate! Main goal is to help specification discussion on this and start with a reasonable initial implementation.
---
Patch is 128.21 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/228747.diff
28 Files Affected:
- (modified) flang/lib/Lower/Bridge.cpp (+18)
- (modified) flang/lib/Lower/ConvertVariable.cpp (+20-1)
- (modified) flang/lib/Lower/OpenMP/Utils.cpp (+8)
- (modified) flang/lib/Lower/OpenMP/Utils.h (+8)
- (modified) flang/lib/Optimizer/OpenMP/MapInfoFinalization.cpp (+211-44)
- (modified) flang/lib/Semantics/check-omp-structure.cpp (+108)
- (modified) flang/lib/Semantics/check-omp-structure.h (+2)
- (added) flang/test/Fir/OpenMP/polymorphic-rtti-declare-target.f90 (+58)
- (modified) flang/test/Integration/OpenMP/map-types-and-sizes.f90 (+403-2)
- (modified) flang/test/Lower/OpenMP/allocatable-dtype-intermediate-map-gen.f90 (+1-1)
- (added) flang/test/Lower/OpenMP/polymorphic-derived-type-map.f90 (+50)
- (added) flang/test/Semantics/OpenMP/target-polymorphic-derived-type-version.f90 (+111)
- (added) flang/test/Transforms/omp-map-info-finalization-polymorphic.fir (+43)
- (added) offload/test/offloading/fortran/target-implicit-map-polymorphic-dispatch.f90 (+218)
- (added) offload/test/offloading/fortran/target-map-polymorphic-abstract-base-rtti.f90 (+84)
- (added) offload/test/offloading/fortran/target-map-polymorphic-abstract-type-bound-dispatch.f90 (+128)
- (added) offload/test/offloading/fortran/target-map-polymorphic-array-rtti.f90 (+66)
- (added) offload/test/offloading/fortran/target-map-polymorphic-array-section-type-bound-dispatch.f90 (+160)
- (added) offload/test/offloading/fortran/target-map-polymorphic-array-type-bound-dispatch.f90 (+156)
- (added) offload/test/offloading/fortran/target-map-polymorphic-derived-type.f90 (+139)
- (added) offload/test/offloading/fortran/target-map-polymorphic-multilevel-type-bound-dispatch.f90 (+156)
- (added) offload/test/offloading/fortran/target-map-polymorphic-nested-rtti.f90 (+82)
- (added) offload/test/offloading/fortran/target-map-polymorphic-pointer-rtti.f90 (+71)
- (added) offload/test/offloading/fortran/target-map-polymorphic-pointer-type-bound-dispatch.f90 (+138)
- (added) offload/test/offloading/fortran/target-map-polymorphic-remap-rtti.f90 (+112)
- (added) offload/test/offloading/fortran/target-map-polymorphic-rtti-intrinsics.f90 (+112)
- (added) offload/test/offloading/fortran/target-map-polymorphic-same-type-as.f90 (+93)
- (added) offload/test/offloading/fortran/target-map-polymorphic-type-bound-dispatch.f90 (+95)
``````````diff
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 9a35b82b8f20ca..ba4a8482f6eba1 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -68,6 +68,8 @@
#include "flang/Support/Flags.h"
#include "flang/Support/Version.h"
#include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
+#include "mlir/Dialect/OpenMP/OpenMPInterfaces.h"
+#include "mlir/Dialect/OpenMP/Utils/Utils.h"
#include "mlir/Dialect/SCF/IR/SCF.h"
#include "mlir/IR/BuiltinAttributes.h"
#include "mlir/IR/Matchers.h"
@@ -84,6 +86,7 @@
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Target/TargetMachine.h"
+#include "OpenMP/Utils.h"
#include <optional>
#define DEBUG_TYPE "flang-lower-bridge"
@@ -494,6 +497,21 @@ class TypeInfoConverter {
builder, info.loc,
mlir::StringAttr::get(builder.getContext(), tbpName),
mlir::SymbolRefAttr::get(builder.getContext(), bindingName));
+
+ // Type-bound dispatch tables store procedure addresses in runtime
+ // TypeDescriptor metadata. If the TypeDescriptor is registered for
+ // OpenMP offload, the referenced procedures must also be available in
+ // the device image so device-side dispatch table entries can refer to
+ // device functions.
+ if (converter.getFoldingContext().languageFeatures().IsEnabled(
+ Fortran::common::LanguageFeature::OpenMP) &&
+ mlir::omp::getOpenMPVersionAttribute(converter.getModuleOp(),
+ /*fallback=*/0) >= 61)
+ if (mlir::Operation *bindingOp =
+ builder.getModule().lookupSymbol(bindingName))
+ Fortran::lower::omp::markDeclareTarget(bindingOp,
+ /*implicit=*/true);
+
// Propagate DEFERRED attribute on the binding to fir.dt_entry.
if (binding.get().attrs().test(Fortran::semantics::Attr::DEFERRED))
dtEntry->setAttr(fir::DTEntryOp::getDeferredAttrNameStr(),
diff --git a/flang/lib/Lower/ConvertVariable.cpp b/flang/lib/Lower/ConvertVariable.cpp
index 553032bb3909e7..eb9a1100d268a5 100644
--- a/flang/lib/Lower/ConvertVariable.cpp
+++ b/flang/lib/Lower/ConvertVariable.cpp
@@ -48,6 +48,8 @@
#include "flang/Semantics/type.h"
#include "mlir/Dialect/Complex/IR/Complex.h"
#include "mlir/Dialect/OpenACC/OpenACC.h"
+#include "mlir/Dialect/OpenMP/Utils/Utils.h"
+#include "OpenMP/Utils.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/CommandLine.h"
@@ -3377,7 +3379,24 @@ void Fortran::lower::createRuntimeTypeInfoGlobal(
std::string globalName = converter.mangleName(typeInfoSym);
auto var = Fortran::lower::pft::Variable(typeInfoSym, /*global=*/true);
fir::LinkageAttr linkage = getLinkageAttribute(converter, var);
- defineGlobal(converter, var, globalName, linkage);
+ fir::GlobalOp global = defineGlobal(converter, var, globalName, linkage);
+
+ // For OpenMP we make the compiler generated RTTI objects declare-target
+ // globals so that we do not have to transfer the RTTI to device on each map
+ // of a RTTI dependent type and all RTTI remains consistent on device, in
+ // particular the polymorphic function dispatch table, the RTTI and the dispatch
+ // functions are lowered to device and have device consistent addresses through
+ // declare target, and we simply have to then redirect any mapped polymorphic
+ // types descriptor to point at this global type information to access the
+ // device side dispatch table for the type and any other RTTI that's required
+ // for things like SELECT statements, dynamic variable access and polymorphic
+ // intrinsic functions.
+ if (converter.getFoldingContext().languageFeatures().IsEnabled(
+ Fortran::common::LanguageFeature::OpenMP) &&
+ mlir::omp::getOpenMPVersionAttribute(converter.getModuleOp(),
+ /*fallback=*/0) >= 61)
+ Fortran::lower::omp::markDeclareTarget(global.getOperation(),
+ /*implicit=*/false);
}
mlir::Type Fortran::lower::getCrayPointeeBoxType(mlir::Type fortranType) {
diff --git a/flang/lib/Lower/OpenMP/Utils.cpp b/flang/lib/Lower/OpenMP/Utils.cpp
index e05a3eab6fad6d..87d75336e69a96 100644
--- a/flang/lib/Lower/OpenMP/Utils.cpp
+++ b/flang/lib/Lower/OpenMP/Utils.cpp
@@ -172,6 +172,14 @@ void gatherFuncAndVarSyms(
symbolAndClause.emplace_back(clause, *object.sym(), automap);
}
+void markDeclareTarget(mlir::Operation *op, bool implicit) {
+ if (auto declareTargetOp =
+ llvm::dyn_cast<mlir::omp::DeclareTargetInterface>(op))
+ declareTargetOp.setDeclareTarget(mlir::omp::DeclareTargetDeviceType::any,
+ mlir::omp::DeclareTargetCaptureClause::to,
+ /*automap=*/false, implicit);
+}
+
// This function gathers the individual omp::Object's that make up a
// larger omp::Object symbol.
//
diff --git a/flang/lib/Lower/OpenMP/Utils.h b/flang/lib/Lower/OpenMP/Utils.h
index 4560c9df349b2d..70439877bc1786 100644
--- a/flang/lib/Lower/OpenMP/Utils.h
+++ b/flang/lib/Lower/OpenMP/Utils.h
@@ -22,6 +22,10 @@
extern llvm::cl::opt<bool> treatIndexAsSection;
+namespace mlir {
+class Operation;
+} // namespace mlir
+
namespace fir {
class FirOpBuilder;
class RecordType;
@@ -162,6 +166,10 @@ void gatherFuncAndVarSyms(
llvm::SmallVectorImpl<DeclareTargetCaptureInfo> &symbolAndClause,
bool automap = false);
+/// If \p op implements the OpenMP DeclareTargetInterface, mark it as declare
+/// target with device_type=any, capture=to, automap=false. No-op otherwise.
+void markDeclareTarget(mlir::Operation *op, bool implicit);
+
int64_t getCollapseValue(const List<Clause> &clauses);
void genObjectList(const ObjectList &objects,
diff --git a/flang/lib/Optimizer/OpenMP/MapInfoFinalization.cpp b/flang/lib/Optimizer/OpenMP/MapInfoFinalization.cpp
index 8046a702f330a7..efdd7a10986b19 100644
--- a/flang/lib/Optimizer/OpenMP/MapInfoFinalization.cpp
+++ b/flang/lib/Optimizer/OpenMP/MapInfoFinalization.cpp
@@ -33,8 +33,10 @@
#include "flang/Optimizer/HLFIR/HLFIROps.h"
#include "flang/Optimizer/OpenMP/Passes.h"
#include "mlir/Analysis/SliceAnalysis.h"
+#include "mlir/Dialect/Arith/IR/Arith.h"
#include "mlir/Dialect/Func/IR/FuncOps.h"
#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
+#include "mlir/Dialect/OpenMP/Utils/Utils.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/Operation.h"
#include "mlir/IR/SymbolTable.h"
@@ -548,6 +550,93 @@ class MapInfoFinalizationPass
return mapType;
}
+ static bool shouldMapDescriptorTypeDesc(mlir::Value descriptor,
+ bool supportsPolymorphicMap) {
+ if (!supportsPolymorphicMap)
+ return false;
+ auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(
+ fir::unwrapRefType(descriptor.getType()));
+ return boxTy && fir::isPolymorphicType(boxTy) && fir::boxHasAddendum(boxTy);
+ }
+
+ static bool shouldMapPolymorphicDescriptorWithRuntimeElementSize(
+ mlir::Value descriptor, bool supportsPolymorphicMap) {
+ if (!supportsPolymorphicMap)
+ return false;
+ auto boxTy = mlir::dyn_cast<fir::BaseBoxType>(
+ fir::unwrapRefType(descriptor.getType()));
+ return boxTy && fir::isPolymorphicType(boxTy);
+ }
+
+ mlir::Value getAsIndex(mlir::Location loc, mlir::Value value,
+ fir::FirOpBuilder &builder) {
+ if (value.getType() == builder.getIndexType())
+ return value;
+ return builder.createConvert(loc, builder.getIndexType(), value);
+ }
+
+ /// For polymorphic boxes, we currently need to readjust the bounds to
+ /// use the descriptor's elem_len as the dynamic type may extend the
+ /// declared type on the map at runtime. So we turn the bounds calculation
+ /// into a 1-D byte mapping so polymorphic objects and arrays are sized by
+ /// the runtime element length.
+ ///
+ /// This could in theory be incorporated into the earlier lowering stage,
+ /// but there's a number of areas in the lowering that require bounds
+ /// adjustments and a number of passes that themselves generate maps that
+ /// may depend on this regeneration, so this is for the moment the most
+ /// consistent place for re-adjustment of these cases, and generally we
+ /// adjust a lot of the descriptor / data relationship here as we expand
+ /// into multiple maps.
+ llvm::SmallVector<mlir::Value>
+ genRuntimeSizedBaseAddrBounds(mlir::Location loc, mlir::Value descriptor,
+ mlir::ValueRange existingBounds,
+ fir::FirOpBuilder &builder) {
+ mlir::Type idxTy = builder.getIndexType();
+ mlir::Value zero = builder.createIntegerConstant(loc, idxTy, 0);
+ mlir::Value one = builder.createIntegerConstant(loc, idxTy, 1);
+ mlir::Value box = descriptor;
+ if (fir::isa_ref_type(box.getType()))
+ box = fir::LoadOp::create(builder, loc, box);
+ mlir::Value elemSize = fir::BoxEleSizeOp::create(builder, loc, idxTy, box);
+
+ mlir::Value elemCount = one;
+ mlir::Value elemOffset = zero;
+ for (mlir::Value bound : llvm::reverse(existingBounds)) {
+ auto boundOp = mlir::dyn_cast_if_present<mlir::omp::MapBoundsOp>(
+ bound.getDefiningOp());
+ if (!boundOp)
+ continue;
+ mlir::Value lowerBound =
+ getAsIndex(loc, boundOp.getLowerBound(), builder);
+ mlir::Value upperBound =
+ getAsIndex(loc, boundOp.getUpperBound(), builder);
+ mlir::Value extent = getAsIndex(loc, boundOp.getExtent(), builder);
+ mlir::Value boundElemCount = mlir::arith::AddIOp::create(
+ builder, loc,
+ mlir::arith::SubIOp::create(builder, loc, upperBound, lowerBound),
+ one);
+ elemCount =
+ mlir::arith::MulIOp::create(builder, loc, elemCount, boundElemCount);
+ elemOffset = mlir::arith::AddIOp::create(
+ builder, loc,
+ mlir::arith::MulIOp::create(builder, loc, elemOffset, extent),
+ lowerBound);
+ }
+
+ mlir::Value byteOffset =
+ mlir::arith::MulIOp::create(builder, loc, elemOffset, elemSize);
+ mlir::Value byteExtent =
+ mlir::arith::MulIOp::create(builder, loc, elemCount, elemSize);
+ mlir::Value upperBound = mlir::arith::SubIOp::create(
+ builder, loc,
+ mlir::arith::AddIOp::create(builder, loc, byteOffset, byteExtent), one);
+ mlir::Type mapBoundsTy = builder.getType<mlir::omp::MapBoundsType>();
+ return {mlir::omp::MapBoundsOp::create(
+ builder, loc, mapBoundsTy, byteOffset, upperBound, byteExtent, one,
+ /*strideInBytes=*/true, zero)};
+ }
+
/// Function that generates a FIR operation accessing the descriptor's
/// base address (BoxOffsetOp) and a MapInfoOp for it. The most
/// important thing to note is that we normally move the bounds from
@@ -557,11 +646,14 @@ class MapInfoFinalizationPass
/// descriptor map before this pass splits it). Lowering attaches a NameLoc
/// there for the Fortran map text. This is used with new Ops being
/// created by this function.
+ /// \p parentOp is the MapInfoOp being expanded (the descriptor map before
+ /// this pass splits it). Lowering attaches a NameLoc there for the Fortran
+ /// map text. New ops created here use its location so NameLoc is preserved.
mlir::omp::MapInfoOp
genBaseAddrMap(mlir::Location mapInfoOpLoc, mlir::Value descriptor,
mlir::omp::MapInfoOp parentOp,
mlir::omp::ClauseMapFlags mapType, fir::FirOpBuilder &builder,
- bool isRefPtee = false,
+ bool supportsPolymorphicMap, bool isRefPtee = false,
mlir::FlatSymbolRefAttr mapperId = mlir::FlatSymbolRefAttr()) {
mlir::Value baseAddr = fir::BoxOffsetOp::create(
builder, mapInfoOpLoc, descriptor, fir::BoxFieldAttr::base_addr);
@@ -577,6 +669,15 @@ class MapInfoFinalizationPass
mlir::Type underlyingDescType = fir::unwrapRefType(descriptor.getType());
+ llvm::SmallVector<mlir::Value> bounds(parentOp.getBounds().begin(),
+ parentOp.getBounds().end());
+ if (shouldMapPolymorphicDescriptorWithRuntimeElementSize(
+ descriptor, supportsPolymorphicMap)) {
+ bounds = genRuntimeSizedBaseAddrBounds(mapInfoOpLoc, descriptor,
+ parentOp.getBounds(), builder);
+ underlyingBaseAddrType = builder.getI8Type();
+ }
+
// Member of the descriptor pointing at the allocated data
return mlir::omp::MapInfoOp::create(
builder, mapInfoOpLoc, baseAddr.getType(), descriptor,
@@ -587,8 +688,7 @@ class MapInfoFinalizationPass
mlir::omp::VariableCaptureKind::ByRef),
baseAddr, mlir::TypeAttr::get(underlyingBaseAddrType),
isRefPtee ? parentOp.getMembers() : mlir::SmallVector<mlir::Value>{},
- isRefPtee ? parentOp.getMembersIndexAttr() : mlir::ArrayAttr{},
- parentOp.getBounds(),
+ isRefPtee ? parentOp.getMembersIndexAttr() : mlir::ArrayAttr{}, bounds,
/*mapperId=*/mapperId,
/*name=*/builder.getStringAttr(""),
/*partial_map=*/builder.getBoolAttr(false));
@@ -986,6 +1086,35 @@ class MapInfoFinalizationPass
return baseAddrType;
}
+ mlir::Operation *genImplicitPointerAttachMap(
+ mlir::omp::MapInfoOp descMapOp, mlir::Value attachBase,
+ mlir::Type attachBaseType, mlir::Value pointerSlotAddr,
+ mlir::Type pointerSlotPointeeType, mlir::ValueRange bounds,
+ llvm::SmallVectorImpl<ParentAndPlacement> &mapMemberUsers,
+ mlir::Operation *target, fir::FirOpBuilder &builder,
+ mlir::omp::ClauseMapFlags refFlagType, mlir::Type resultType,
+ bool isAttachAlways = false) {
+ auto implicitAttachMap = mlir::omp::MapInfoOp::create(
+ builder, descMapOp->getLoc(), resultType, attachBase,
+ mlir::TypeAttr::get(attachBaseType),
+ builder.getAttr<mlir::omp::ClauseMapFlagsAttr>(
+ mlir::omp::ClauseMapFlags::attach | refFlagType |
+ (isAttachAlways ? mlir::omp::ClauseMapFlags::always
+ : mlir::omp::ClauseMapFlags::none)),
+ descMapOp.getMapCaptureTypeAttr(), /*varPtrPtr=*/
+ pointerSlotAddr, mlir::TypeAttr::get(pointerSlotPointeeType),
+ /*members=*/mlir::SmallVector<mlir::Value>{},
+ /*membersIndex=*/mlir::ArrayAttr{}, bounds,
+ /*mapperId*/ mlir::FlatSymbolRefAttr(), descMapOp.getNameAttr(),
+ /*partial_map=*/builder.getBoolAttr(false));
+
+ // Has to be added to the target immediately, as we expect all maps
+ // processed by this pass to have a user that is a target.
+ addAttachMemberToTarget(descMapOp, implicitAttachMap, mapMemberUsers,
+ builder, target);
+ return implicitAttachMap;
+ }
+
/// This function generates an attach map, which is an type of OpenMP map that
/// binds a pointer to its data. In the case of Fortran, this binding is
/// primarily for binding the pointer inside of descriptors to the underlying
@@ -1001,7 +1130,8 @@ class MapInfoFinalizationPass
llvm::SmallVectorImpl<ParentAndPlacement> &mapMemberUsers,
mlir::Operation *target, fir::FirOpBuilder &builder,
mlir::omp::ClauseMapFlags refFlagType, bool isAttachAlways = false,
- mlir::Value reuseBaseAddr = mlir::Value{}) {
+ mlir::Value reuseBaseAddr = mlir::Value{},
+ bool supportsPolymorphicMap = false) {
auto baseAddr =
reuseBaseAddr
? reuseBaseAddr
@@ -1009,28 +1139,44 @@ class MapInfoFinalizationPass
fir::BoxFieldAttr::base_addr);
mlir::Type underlyingVarType = getUnderlyingVarType(baseAddr.getType());
+ llvm::SmallVector<mlir::Value> bounds(descMapOp.getBounds().begin(),
+ descMapOp.getBounds().end());
+ if (shouldMapPolymorphicDescriptorWithRuntimeElementSize(
+ descriptor, supportsPolymorphicMap)) {
+ bounds = genRuntimeSizedBaseAddrBounds(descMapOp->getLoc(), descriptor,
+ descMapOp.getBounds(), builder);
+ underlyingVarType = builder.getI8Type();
+ }
+ mlir::Type runtimePtrType = fir::unwrapRefType(descriptor.getType());
- auto implicitAttachMap = mlir::omp::MapInfoOp::create(
- builder, descMapOp->getLoc(), descMapOp.getResult().getType(),
- descriptor,
- mlir::TypeAttr::get(fir::unwrapRefType(descriptor.getType())),
- builder.getAttr<mlir::omp::ClauseMapFlagsAttr>(
- mlir::omp::ClauseMapFlags::attach | refFlagType |
- (isAttachAlways ? mlir::omp::ClauseMapFlags::always
- : mlir::omp::ClauseMapFlags::none)),
- descMapOp.getMapCaptureTypeAttr(), /*varPtrPtr=*/
- baseAddr, mlir::TypeAttr::get(underlyingVarType),
- /*members=*/mlir::SmallVector<mlir::Value>{},
- /*membersIndex=*/mlir::ArrayAttr{},
- /*bounds=*/descMapOp.getBounds(),
- /*mapperId*/ mlir::FlatSymbolRefAttr(), descMapOp.getNameAttr(),
- /*partial_map=*/builder.getBoolAttr(false));
+ return genImplicitPointerAttachMap(
+ descMapOp, descriptor, runtimePtrType, baseAddr, underlyingVarType,
+ bounds, mapMemberUsers, target, builder, refFlagType,
+ descMapOp.getResult().getType(), isAttachAlways);
+ }
- // Has to be added to the target immediately, as we expect all maps
- // processed by this pass to have a user that is a target.
- addAttachMemberToTarget(descMapOp, implicitAttachMap, mapMemberUsers,
- builder, target);
- return implicitAttachMap;
+ [[maybe_unused]] mlir::Operation *genImplicitTypeDescAttachMap(
+ mlir::omp::MapInfoOp descMapOp, mlir::Value descriptor,
+ llvm::SmallVectorImpl<ParentAndPlacement> &mapMemberUsers,
+ mlir::Operation *target, fir::FirOpBuilder &builder,
+ mlir::omp::ClauseMapFlags refFlagType, bool isAttachAlways = false) {
+ auto typeDescFieldAddr =
+ fir::BoxOffsetOp::create(builder, descMapOp->getLoc(), descriptor,
+ fir::BoxFieldAttr::derived_type);
+
+ // This attach entry binds the device copy of the dynamic type descriptor to
+ // the descriptor addendum's derived_type pointer slot. The var_ptr must
+ // therefore be the address of that pointer slot in the originating
+ // descriptor, not the descriptor base address. Model both var_ptr and
+ // var_ptr_ptr as pointer-sized objects for this attach map so lowering
+ // produces an 8-byte pointer attach entry.
+ mlir::Type runtimePtrType =
+ fir::LLVMPointerType::get(builder.getContext(), builder.getI8Type());
+
+ return genImplicitPointerAttachMap(
+ descMapOp, typeDescFieldAddr, runtimePtrType, typeDescFieldAddr,
+ runtimePtrType, mlir::ValueRange{}, mapMemberUsers, target, builder,
+ refFlagType, typeDescFieldAddr.getType(), isAttachAlways);
}
// If the operation that we are expanding with a descriptor has a user
@@ -1103,7 +1249,8 @@ class MapInfoFinalizationPass
genRefPtrMap(mlir::omp::MapInfoOp op, fir::FirOpBuilder &builder,
mlir::Operation *target, mlir::Value descriptor,
llvm::SmallVectorImpl<ParentAndPlacement> &mapMemberUsers,
- bool isAttachNever, bool isAttachAlways) {
+ bool isAttachNever, bool isAttachAlways,
+ bool supportsPolymorphicMap) {
auto newMapInfoOp = mlir::omp::MapInfoOp::create(
builder, op->getLoc(), op.getResult().getType(), descriptor,
mlir::TypeAttr::get(fir::unwrapRefType(descriptor.getType())),
@@ -1117,7 +1264,15 @@ class MapInfoFinalizationPass
if (!isAttachNever)
genImplicitAttachMap(op, descriptor, mapMemberUsers, target, builder,
- mlir::omp::ClauseMapFlags::ref_ptr, isAttachAlways);
+ mlir::omp::ClauseMapFlags::ref_ptr, isAttachAlways,
+ /*reuseBaseAddr=*/mlir::Value{},
+ supportsPolymorphicMap);
+
+ if (shouldMapDescriptorTypeDesc(descriptor, supportsPolymorphicMap))
+ genImplicitTypeDescAttachMap(op, descriptor, mapMemberUsers, target...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/228747
More information about the flang-commits
mailing list