[llvm-branch-commits] [llvm] [mlir] [OpenMP][mlir] Support iterator modifier LLVM lowering for map/motion (PR #199101)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Tue Jun 9 21:03:46 PDT 2026
https://github.com/chichunchen updated https://github.com/llvm/llvm-project/pull/199101
>From d27400783bebaa4330d951e9792765191293c1c1 Mon Sep 17 00:00:00 2001
From: "Chi Chun, Chen" <chichun.chen at hpe.com>
Date: Tue, 12 May 2026 22:52:37 -0500
Subject: [PATCH] [OpenMP][mlir] Support iterator modifier LLVM lowering for
map/motion
Lower iterator modifiers on map and motion
(target_data/target_data_begin/target_data_end/target_update) by
building dynamic offload map arrays in OpenMPIRBuilder and populating
them from iterator-expanded map entries during MLIR OpenMP to LLVM IR
translation.
Hoist runtime-sized offload map array allocation for target data with
iterator modifiers so the dynamic count and arrays dominate runtime calls.
This patch is part of feature work for #188061.
Assisted with copilot.
---
.../llvm/Frontend/OpenMP/OMPIRBuilder.h | 38 ++-
llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp | 257 ++++++++++++++-
.../Frontend/OpenMPIRBuilderTest.cpp | 126 +++++++
.../OpenMP/OpenMPToLLVMIRTranslation.cpp | 165 +++++++++-
mlir/test/Target/LLVMIR/openmp-iterator.mlir | 308 ++++++++++++++++++
mlir/test/Target/LLVMIR/openmp-todo.mlir | 82 +----
.../fortran/map-motion-iterator.f90 | 119 +++++++
7 files changed, 1000 insertions(+), 95 deletions(-)
create mode 100644 offload/test/offloading/fortran/map-motion-iterator.f90
diff --git a/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h b/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h
index 128fb7af7152a..5b7e7cf8e5203 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h
+++ b/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h
@@ -2824,6 +2824,9 @@ class OpenMPIRBuilder {
/// Whether the `target ... data` directive has a `nowait` clause.
bool HasNoWait = false;
+ /// Total number of map entries when the number is computed at runtime.
+ Value *TotalMapCount = nullptr;
+
explicit TargetDataInfo() = default;
explicit TargetDataInfo(bool RequiresDevicePointerInfo,
bool SeparateBeginEndCalls)
@@ -2839,7 +2842,8 @@ class OpenMPIRBuilder {
bool isValid() {
return RTArgs.BasePointersArray && RTArgs.PointersArray &&
RTArgs.SizesArray && RTArgs.MapTypesArray &&
- (!HasMapper || RTArgs.MappersArray) && NumberOfPtrs;
+ (!HasMapper || RTArgs.MappersArray) &&
+ (NumberOfPtrs || TotalMapCount);
}
bool requiresDevicePointerInfo() { return RequiresDevicePointerInfo; }
bool separateBeginEndCalls() { return SeparateBeginEndCalls; }
@@ -2906,6 +2910,27 @@ class OpenMPIRBuilder {
using CustomMapperCallbackTy =
function_ref<Expected<Function *>(unsigned int)>;
+ /// Callback for filling dynamic map entries after static entries have been
+ /// emitted into the offloading arrays.
+ using DynMapEntriesCallbackTy =
+ function_ref<Error(InsertPointTy CodeGenIP, TargetDataRTArgs &RTArgs,
+ unsigned int StaticCount)>;
+
+ /// Store a single map entry into the offloading arrays at \p Index.
+ LLVM_ABI void emitOffloadingArraysMapEntry(
+ IRBuilderBase &Builder, TargetDataRTArgs &RTArgs, TargetDataInfo &Info,
+ Value *Index, Value *BasePtr, Value *Ptr, Value *Size, Value *MapType,
+ Value *MapTypeEnd = nullptr, Value *MapperFunc = nullptr,
+ Value *MapName = nullptr, DeviceInfoTy DevPtrType = DeviceInfoTy::None,
+ InsertPointTy AllocaIP = {}, unsigned DeviceAddrCBIndex = 0,
+ function_ref<void(unsigned int, Value *)> DeviceAddrCB = nullptr);
+
+ /// Allocate runtime-sized offloading arrays using \p Info.TotalMapCount.
+ LLVM_ABI void emitDynamicOffloadingArraysAllocas(InsertPointTy AllocaIP,
+ InsertPointTy CodeGenIP,
+ TargetDataInfo &Info,
+ bool EmitDebug);
+
/// Generate a target region entry call and host fallback call.
///
/// \param Loc The location at which the request originated and is fulfilled.
@@ -2973,7 +2998,8 @@ class OpenMPIRBuilder {
InsertPointTy AllocaIP, InsertPointTy CodeGenIP, MapInfosTy &CombinedInfo,
TargetDataInfo &Info, CustomMapperCallbackTy CustomMapperCB,
bool IsNonContiguous = false,
- function_ref<void(unsigned int, Value *)> DeviceAddrCB = nullptr);
+ function_ref<void(unsigned int, Value *)> DeviceAddrCB = nullptr,
+ DynMapEntriesCallbackTy DynMapEntriesCB = nullptr);
/// Allocates memory for and populates the arrays required for offloading
/// (offload_{baseptrs|ptrs|mappers|sizes|maptypes|mapnames}). Then, it
@@ -2986,7 +3012,8 @@ class OpenMPIRBuilder {
TargetDataRTArgs &RTArgs, MapInfosTy &CombinedInfo,
CustomMapperCallbackTy CustomMapperCB, bool IsNonContiguous = false,
bool ForEndCall = false,
- function_ref<void(unsigned int, Value *)> DeviceAddrCB = nullptr);
+ function_ref<void(unsigned int, Value *)> DeviceAddrCB = nullptr,
+ DynMapEntriesCallbackTy DynMapEntriesCB = nullptr);
/// Creates offloading entry for the provided entry ID \a ID, address \a
/// Addr, size \a Size, and flags \a Flags.
@@ -3609,6 +3636,8 @@ class OpenMPIRBuilder {
/// \param BodyGenCB Optional Callback to generate the region code.
/// \param DeviceAddrCB Optional callback to generate code related to
/// use_device_ptr and use_device_addr.
+ /// \param SrcLocInfo Optional source location information.
+ /// \param DynMapEntriesCB Optional callback to fill dynamic map entries.
LLVM_ABI InsertPointOrErrorTy createTargetData(
const LocationDescription &Loc, InsertPointTy AllocaIP,
InsertPointTy CodeGenIP, ArrayRef<BasicBlock *> DeallocBlocks,
@@ -3619,7 +3648,8 @@ class OpenMPIRBuilder {
BodyGenTy BodyGenType)>
BodyGenCB = nullptr,
function_ref<void(unsigned int, Value *)> DeviceAddrCB = nullptr,
- Value *SrcLocInfo = nullptr);
+ Value *SrcLocInfo = nullptr,
+ DynMapEntriesCallbackTy DynMapEntriesCB = nullptr);
using TargetBodyGenCallbackTy = function_ref<InsertPointOrErrorTy(
InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
diff --git a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
index 92eb7de0d882f..1b6dd7b05313b 100644
--- a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
+++ b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp
@@ -8489,30 +8489,45 @@ OpenMPIRBuilder::InsertPointOrErrorTy OpenMPIRBuilder::createTargetData(
function_ref<InsertPointOrErrorTy(InsertPointTy CodeGenIP,
BodyGenTy BodyGenType)>
BodyGenCB,
- function_ref<void(unsigned int, Value *)> DeviceAddrCB, Value *SrcLocInfo) {
+ function_ref<void(unsigned int, Value *)> DeviceAddrCB, Value *SrcLocInfo,
+ DynMapEntriesCallbackTy DynMapEntriesCB) {
if (!updateToLocation(Loc))
return InsertPointTy();
Builder.restoreIP(CodeGenIP);
bool IsStandAlone = !BodyGenCB;
- MapInfosTy *MapInfo;
+ MapInfosTy *MapInfo = nullptr;
+
+ if (!IsStandAlone && DynMapEntriesCB) {
+ MapInfo = &GenMapInfoCB(Builder.saveIP());
+ if (Info.TotalMapCount)
+ emitDynamicOffloadingArraysAllocas(AllocaIP, Builder.saveIP(), Info,
+ DynMapEntriesCB ||
+ !MapInfo->Names.empty());
+ }
+
// Generate the code for the opening of the data environment. Capture all the
// arguments of the runtime call by reference because they are used in the
// closing of the region.
auto BeginThenGen = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
ArrayRef<BasicBlock *> DeallocBlocks) -> Error {
- MapInfo = &GenMapInfoCB(Builder.saveIP());
+ if (!MapInfo)
+ MapInfo = &GenMapInfoCB(Builder.saveIP());
if (Error Err = emitOffloadingArrays(
AllocaIP, Builder.saveIP(), *MapInfo, Info, CustomMapperCB,
- /*IsNonContiguous=*/true, DeviceAddrCB))
+ /*IsNonContiguous=*/true, DeviceAddrCB, DynMapEntriesCB))
return Err;
TargetDataRTArgs RTArgs;
emitOffloadingArraysArgument(Builder, RTArgs, Info);
// Emit the number of elements in the offloading arrays.
- Value *PointerNum = Builder.getInt32(Info.NumberOfPtrs);
+ Value *PointerNum =
+ Info.TotalMapCount
+ ? Builder.CreateIntCast(Info.TotalMapCount, Builder.getInt32Ty(),
+ /*isSigned=*/false, "map.count")
+ : Builder.getInt32(Info.NumberOfPtrs);
// Source location for the ident struct
if (!SrcLocInfo) {
@@ -8603,11 +8618,15 @@ OpenMPIRBuilder::InsertPointOrErrorTy OpenMPIRBuilder::createTargetData(
auto EndThenGen = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP,
ArrayRef<BasicBlock *> DeallocBlocks) {
TargetDataRTArgs RTArgs;
- Info.EmitDebug = !MapInfo->Names.empty();
+ Info.EmitDebug = Info.EmitDebug || !MapInfo->Names.empty();
emitOffloadingArraysArgument(Builder, RTArgs, Info, /*ForEndCall=*/true);
// Emit the number of elements in the offloading arrays.
- Value *PointerNum = Builder.getInt32(Info.NumberOfPtrs);
+ Value *PointerNum =
+ Info.TotalMapCount
+ ? Builder.CreateIntCast(Info.TotalMapCount, Builder.getInt32Ty(),
+ /*isSigned=*/false, "map.count")
+ : Builder.getInt32(Info.NumberOfPtrs);
// Source location for the ident struct
if (!SrcLocInfo) {
@@ -9621,10 +9640,11 @@ Error OpenMPIRBuilder::emitOffloadingArraysAndArgs(
InsertPointTy AllocaIP, InsertPointTy CodeGenIP, TargetDataInfo &Info,
TargetDataRTArgs &RTArgs, MapInfosTy &CombinedInfo,
CustomMapperCallbackTy CustomMapperCB, bool IsNonContiguous,
- bool ForEndCall, function_ref<void(unsigned int, Value *)> DeviceAddrCB) {
- if (Error Err =
- emitOffloadingArrays(AllocaIP, CodeGenIP, CombinedInfo, Info,
- CustomMapperCB, IsNonContiguous, DeviceAddrCB))
+ bool ForEndCall, function_ref<void(unsigned int, Value *)> DeviceAddrCB,
+ DynMapEntriesCallbackTy DynMapEntriesCB) {
+ if (Error Err = emitOffloadingArrays(AllocaIP, CodeGenIP, CombinedInfo, Info,
+ CustomMapperCB, IsNonContiguous,
+ DeviceAddrCB, DynMapEntriesCB))
return Err;
emitOffloadingArraysArgument(Builder, RTArgs, Info, ForEndCall);
return Error::success();
@@ -10012,7 +10032,7 @@ void OpenMPIRBuilder::emitOffloadingArraysArgument(IRBuilderBase &Builder,
auto Int64Ty = Type::getInt64Ty(M.getContext());
auto Int64PtrTy = UnqualPtrTy;
- if (!Info.NumberOfPtrs) {
+ if (!Info.NumberOfPtrs && !Info.TotalMapCount) {
RTArgs.BasePointersArray = ConstantPointerNull::get(VoidPtrPtrTy);
RTArgs.PointersArray = ConstantPointerNull::get(VoidPtrPtrTy);
RTArgs.SizesArray = ConstantPointerNull::get(Int64PtrTy);
@@ -10022,6 +10042,29 @@ void OpenMPIRBuilder::emitOffloadingArraysArgument(IRBuilderBase &Builder,
return;
}
+ if (Info.TotalMapCount) {
+ RTArgs.BasePointersArray =
+ Builder.CreatePointerCast(Info.RTArgs.BasePointersArray, VoidPtrPtrTy);
+ RTArgs.PointersArray =
+ Builder.CreatePointerCast(Info.RTArgs.PointersArray, VoidPtrPtrTy);
+ RTArgs.SizesArray =
+ Builder.CreatePointerCast(Info.RTArgs.SizesArray, Int64PtrTy);
+ RTArgs.MapTypesArray =
+ Builder.CreatePointerCast(ForEndCall && Info.RTArgs.MapTypesArrayEnd
+ ? Info.RTArgs.MapTypesArrayEnd
+ : Info.RTArgs.MapTypesArray,
+ Int64PtrTy);
+ RTArgs.MapNamesArray =
+ Info.EmitDebug
+ ? Builder.CreatePointerCast(Info.RTArgs.MapNamesArray, VoidPtrPtrTy)
+ : ConstantPointerNull::get(VoidPtrPtrTy);
+ RTArgs.MappersArray =
+ Info.HasMapper
+ ? Builder.CreatePointerCast(Info.RTArgs.MappersArray, VoidPtrPtrTy)
+ : ConstantPointerNull::get(VoidPtrPtrTy);
+ return;
+ }
+
RTArgs.BasePointersArray = Builder.CreateConstInBoundsGEP2_32(
ArrayType::get(VoidPtrTy, Info.NumberOfPtrs),
Info.RTArgs.BasePointersArray,
@@ -10116,9 +10159,13 @@ void OpenMPIRBuilder::emitNonContiguousDescriptor(InsertPointTy AllocaIP,
Builder.restoreIP(CodeGenIP);
Value *DAddr = Builder.CreatePointerBitCastOrAddrSpaceCast(
DimsAddr, Builder.getPtrTy());
- Value *P = Builder.CreateConstInBoundsGEP2_32(
- ArrayType::get(Builder.getPtrTy(), Info.NumberOfPtrs),
- Info.RTArgs.PointersArray, 0, I);
+ Value *P = Info.TotalMapCount
+ ? Builder.CreateInBoundsGEP(Builder.getPtrTy(),
+ Info.RTArgs.PointersArray,
+ Builder.getInt64(I))
+ : Builder.CreateConstInBoundsGEP2_32(
+ ArrayType::get(Builder.getPtrTy(), Info.NumberOfPtrs),
+ Info.RTArgs.PointersArray, 0, I);
Builder.CreateAlignedStore(
DAddr, P, M.getDataLayout().getPrefTypeAlign(Builder.getPtrTy()));
++L;
@@ -10423,19 +10470,195 @@ Expected<Function *> OpenMPIRBuilder::emitUserDefinedMapper(
return MapperFn;
}
+void OpenMPIRBuilder::emitOffloadingArraysMapEntry(
+ IRBuilderBase &Builder, TargetDataRTArgs &RTArgs, TargetDataInfo &Info,
+ Value *Index, Value *BasePtr, Value *Ptr, Value *Size, Value *MapType,
+ Value *MapTypeEnd, Value *MapperFunc, Value *MapName,
+ DeviceInfoTy DevPtrType, InsertPointTy AllocaIP, unsigned DeviceAddrCBIndex,
+ function_ref<void(unsigned int, Value *)> DeviceAddrCB) {
+ Type *PtrTy = Builder.getPtrTy();
+ Type *Int64Ty = Builder.getInt64Ty();
+ bool IsDynamic = Info.TotalMapCount != nullptr;
+
+ auto getArrayElementAddress = [&](Value *Array, Type *ElemTy) -> Value * {
+ if (IsDynamic)
+ return Builder.CreateInBoundsGEP(ElemTy, Array, Index);
+ return Builder.CreateInBoundsGEP(ArrayType::get(ElemTy, Info.NumberOfPtrs),
+ Array, {Builder.getInt32(0), Index});
+ };
+
+ Align PtrAlign = M.getDataLayout().getPrefTypeAlign(PtrTy);
+ Align Int64Align = M.getDataLayout().getPrefTypeAlign(Int64Ty);
+
+ Value *BPSlot = getArrayElementAddress(RTArgs.BasePointersArray, PtrTy);
+ Builder.CreateAlignedStore(BasePtr, BPSlot, PtrAlign);
+ Builder.CreateAlignedStore(
+ Ptr, getArrayElementAddress(RTArgs.PointersArray, PtrTy), PtrAlign);
+
+ if (Size)
+ Builder.CreateAlignedStore(
+ Builder.CreateIntCast(Size, Int64Ty, /*isSigned=*/true),
+ getArrayElementAddress(RTArgs.SizesArray, Int64Ty), Int64Align);
+
+ if (MapType)
+ Builder.CreateAlignedStore(
+ Builder.CreateIntCast(MapType, Int64Ty, /*isSigned=*/false),
+ getArrayElementAddress(RTArgs.MapTypesArray, Int64Ty), Int64Align);
+
+ if (RTArgs.MapTypesArrayEnd && MapType)
+ Builder.CreateAlignedStore(
+ Builder.CreateIntCast(MapTypeEnd ? MapTypeEnd : MapType, Int64Ty,
+ /*isSigned=*/false),
+ getArrayElementAddress(RTArgs.MapTypesArrayEnd, Int64Ty), Int64Align);
+
+ Value *Mapper = MapperFunc ? MapperFunc : ConstantPointerNull::get(PtrTy);
+ if (MapperFunc)
+ Info.HasMapper = true;
+ Builder.CreateAlignedStore(
+ Mapper, getArrayElementAddress(RTArgs.MappersArray, PtrTy), PtrAlign);
+
+ if (RTArgs.MapNamesArray && !isa<ConstantPointerNull>(RTArgs.MapNamesArray)) {
+ Value *Name = MapName ? MapName : ConstantPointerNull::get(PtrTy);
+ Builder.CreateAlignedStore(
+ Name, getArrayElementAddress(RTArgs.MapNamesArray, PtrTy), PtrAlign);
+ }
+
+ if (Info.requiresDevicePointerInfo()) {
+ if (DevPtrType == DeviceInfoTy::Pointer) {
+ auto SavedIP = Builder.saveIP();
+ Builder.restoreIP(AllocaIP);
+ Info.DevicePtrInfoMap[BasePtr] = {BPSlot, Builder.CreateAlloca(PtrTy)};
+ Builder.restoreIP(SavedIP);
+ if (DeviceAddrCB)
+ DeviceAddrCB(DeviceAddrCBIndex, Info.DevicePtrInfoMap[BasePtr].second);
+ } else if (DevPtrType == DeviceInfoTy::Address) {
+ Info.DevicePtrInfoMap[BasePtr] = {BPSlot, BPSlot};
+ if (DeviceAddrCB)
+ DeviceAddrCB(DeviceAddrCBIndex, BPSlot);
+ }
+ }
+}
+
+void OpenMPIRBuilder::emitDynamicOffloadingArraysAllocas(
+ InsertPointTy AllocaIP, InsertPointTy CodeGenIP, TargetDataInfo &Info,
+ bool EmitDebug) {
+ assert(Info.TotalMapCount && "expected runtime map entry count");
+
+ Builder.restoreIP(
+ (isa<Constant>(Info.TotalMapCount) || isa<Argument>(Info.TotalMapCount))
+ ? AllocaIP
+ : CodeGenIP);
+ Type *PtrTy = Builder.getPtrTy();
+ Type *Int64Ty = Builder.getInt64Ty();
+ Info.RTArgs.BasePointersArray =
+ Builder.CreateAlloca(PtrTy, Info.TotalMapCount, ".offload_baseptrs");
+ Info.RTArgs.PointersArray =
+ Builder.CreateAlloca(PtrTy, Info.TotalMapCount, ".offload_ptrs");
+ Info.RTArgs.SizesArray =
+ Builder.CreateAlloca(Int64Ty, Info.TotalMapCount, ".offload_sizes");
+ Info.RTArgs.MapTypesArray =
+ Builder.CreateAlloca(Int64Ty, Info.TotalMapCount, ".offload_maptypes");
+ Info.RTArgs.MappersArray =
+ Builder.CreateAlloca(PtrTy, Info.TotalMapCount, ".offload_mappers");
+
+ Info.EmitDebug = Info.EmitDebug || EmitDebug;
+ if (Info.EmitDebug)
+ Info.RTArgs.MapNamesArray =
+ Builder.CreateAlloca(PtrTy, Info.TotalMapCount, ".offload_mapnames");
+ else
+ Info.RTArgs.MapNamesArray =
+ Constant::getNullValue(PointerType::getUnqual(Builder.getContext()));
+
+ if (Info.separateBeginEndCalls())
+ Info.RTArgs.MapTypesArrayEnd = Builder.CreateAlloca(
+ Int64Ty, Info.TotalMapCount, ".offload_maptypes_end");
+
+ restoreIPandDebugLoc(Builder, CodeGenIP);
+}
+
Error OpenMPIRBuilder::emitOffloadingArrays(
InsertPointTy AllocaIP, InsertPointTy CodeGenIP, MapInfosTy &CombinedInfo,
TargetDataInfo &Info, CustomMapperCallbackTy CustomMapperCB,
bool IsNonContiguous,
- function_ref<void(unsigned int, Value *)> DeviceAddrCB) {
+ function_ref<void(unsigned int, Value *)> DeviceAddrCB,
+ DynMapEntriesCallbackTy DynMapEntriesCB) {
+
+ TargetDataRTArgs PreallocatedRTArgs = Info.RTArgs;
+ bool HasPreallocatedDynamicStorage =
+ Info.TotalMapCount && Info.RTArgs.BasePointersArray;
// Reset the array information.
Info.clearArrayInfo();
Info.NumberOfPtrs = CombinedInfo.BasePointers.size();
- if (Info.NumberOfPtrs == 0)
+ if (Info.NumberOfPtrs == 0 && !Info.TotalMapCount)
return Error::success();
+ if (Info.TotalMapCount) {
+ auto mapTypeValue = [&](OpenMPOffloadMappingFlags Flags) {
+ return Builder.getInt64(
+ static_cast<std::underlying_type_t<OpenMPOffloadMappingFlags>>(
+ Flags));
+ };
+ auto endMapTypeValue = [&](OpenMPOffloadMappingFlags Flags) {
+ uint64_t Mapping =
+ static_cast<std::underlying_type_t<OpenMPOffloadMappingFlags>>(Flags);
+ Mapping &=
+ ~static_cast<std::underlying_type_t<OpenMPOffloadMappingFlags>>(
+ OpenMPOffloadMappingFlags::OMP_MAP_PRESENT);
+ return Builder.getInt64(Mapping);
+ };
+
+ Type *PtrTy = Builder.getPtrTy();
+ if (HasPreallocatedDynamicStorage)
+ Info.RTArgs = PreallocatedRTArgs;
+ else
+ emitDynamicOffloadingArraysAllocas(AllocaIP, CodeGenIP, Info,
+ DynMapEntriesCB ||
+ !CombinedInfo.Names.empty());
+
+ for (unsigned I = 0; I < Info.NumberOfPtrs; ++I) {
+ bool IsNonContigEntry =
+ IsNonContiguous &&
+ (static_cast<std::underlying_type_t<OpenMPOffloadMappingFlags>>(
+ CombinedInfo.Types[I] &
+ OpenMPOffloadMappingFlags::OMP_MAP_NON_CONTIG) != 0);
+ Value *Size = CombinedInfo.Sizes[I];
+ if (IsNonContigEntry) {
+ assert(I < CombinedInfo.NonContigInfo.Dims.size() &&
+ "Index must be in-bounds for NON_CONTIG Dims array");
+ const uint64_t DimCount = CombinedInfo.NonContigInfo.Dims[I];
+ assert(DimCount > 0 && "NON_CONTIG DimCount must be > 0");
+ Size = Builder.getInt64(DimCount);
+ }
+
+ Value *MapperFunc = nullptr;
+ auto CustomMFunc = CustomMapperCB(I);
+ if (!CustomMFunc)
+ return CustomMFunc.takeError();
+ if (*CustomMFunc)
+ MapperFunc = Builder.CreatePointerCast(*CustomMFunc, PtrTy);
+
+ Value *MapName =
+ I < CombinedInfo.Names.size() ? CombinedInfo.Names[I] : nullptr;
+ emitOffloadingArraysMapEntry(
+ Builder, Info.RTArgs, Info, Builder.getInt64(I),
+ CombinedInfo.BasePointers[I], CombinedInfo.Pointers[I], Size,
+ mapTypeValue(CombinedInfo.Types[I]),
+ endMapTypeValue(CombinedInfo.Types[I]), MapperFunc, MapName,
+ CombinedInfo.DevicePointers[I], AllocaIP, I, DeviceAddrCB);
+ }
+
+ if (IsNonContiguous && !CombinedInfo.NonContigInfo.Offsets.empty() &&
+ Info.NumberOfPtrs != 0)
+ emitNonContiguousDescriptor(AllocaIP, CodeGenIP, CombinedInfo, Info);
+
+ if (DynMapEntriesCB)
+ return DynMapEntriesCB(Builder.saveIP(), Info.RTArgs, Info.NumberOfPtrs);
+
+ return Error::success();
+ }
+
Builder.restoreIP(AllocaIP);
// Detect if we have any capture size requiring runtime evaluation of the
// size so that a constant array could be eventually used.
diff --git a/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp b/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp
index 23432e2de2287..690d49b4e8c22 100644
--- a/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp
+++ b/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp
@@ -8127,6 +8127,132 @@ TEST_F(OpenMPIRBuilderTest, EmitOffloadingArraysArguments) {
EXPECT_EQ(RTArgs.MapNamesArray->getType(), VoidPtrPtrTy);
}
+TEST_F(OpenMPIRBuilderTest, EmitDynamicOffloadingArraysMapEntries) {
+ OpenMPIRBuilder OMPBuilder(*M);
+ OMPBuilder.Config.setIsGPU(true);
+ OMPBuilder.initialize();
+ IRBuilder<> Builder(BB);
+
+ AllocaInst *StaticPtr =
+ Builder.CreateAlloca(Builder.getInt32Ty(), nullptr, "static.ptr");
+ AllocaInst *DynamicPtr0 =
+ Builder.CreateAlloca(Builder.getInt64Ty(), nullptr, "dynamic.ptr.0");
+ AllocaInst *DynamicPtr1 =
+ Builder.CreateAlloca(Builder.getInt8Ty(), nullptr, "dynamic.ptr.1");
+
+ OpenMPIRBuilder::MapInfosTy CombinedInfo;
+ CombinedInfo.BasePointers.push_back(StaticPtr);
+ CombinedInfo.Pointers.push_back(StaticPtr);
+ CombinedInfo.DevicePointers.push_back(OpenMPIRBuilder::DeviceInfoTy::None);
+ CombinedInfo.Sizes.push_back(Builder.getInt64(4));
+ CombinedInfo.Types.push_back(omp::OpenMPOffloadMappingFlags::OMP_MAP_TO);
+ CombinedInfo.Names.push_back(
+ Builder.CreateGlobalString("static", "static_name", 0, M.get()));
+
+ OpenMPIRBuilder::TargetDataInfo Info(false, false);
+ Info.TotalMapCount = Builder.getInt64(3);
+ OpenMPIRBuilder::TargetDataRTArgs RTArgs;
+ using InsertPointTy = OpenMPIRBuilder::InsertPointTy;
+
+ auto mapTypeValue = [&](omp::OpenMPOffloadMappingFlags Flags) {
+ return Builder.getInt64(
+ static_cast<std::underlying_type_t<omp::OpenMPOffloadMappingFlags>>(
+ Flags));
+ };
+ omp::OpenMPOffloadMappingFlags ToFromMapType =
+ static_cast<omp::OpenMPOffloadMappingFlags>(
+ omp::OpenMPOffloadMappingFlags::OMP_MAP_TO |
+ omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM);
+
+ bool DynamicCBWasCalled = false;
+ auto DynamicMapEntriesCB =
+ [&](InsertPointTy CodeGenIP,
+ OpenMPIRBuilder::TargetDataRTArgs &DynamicRTArgs,
+ unsigned StaticCount) -> Error {
+ DynamicCBWasCalled = true;
+ EXPECT_EQ(StaticCount, 1U);
+ Builder.restoreIP(CodeGenIP);
+ OMPBuilder.emitOffloadingArraysMapEntry(
+ Builder, DynamicRTArgs, Info, Builder.getInt64(StaticCount),
+ DynamicPtr0, DynamicPtr0, Builder.getInt64(8),
+ mapTypeValue(omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM));
+ OMPBuilder.emitOffloadingArraysMapEntry(
+ Builder, DynamicRTArgs, Info, Builder.getInt64(StaticCount + 1),
+ DynamicPtr1, DynamicPtr1, Builder.getInt64(1),
+ mapTypeValue(ToFromMapType));
+ return Error::success();
+ };
+
+ EXPECT_FALSE(OMPBuilder.emitOffloadingArraysAndArgs(
+ InsertPointTy(Builder.saveIP()), InsertPointTy(Builder.saveIP()), Info,
+ RTArgs, CombinedInfo,
+ [](unsigned) -> Expected<Function *> {
+ return static_cast<Function *>(nullptr);
+ },
+ /*IsNonContiguous=*/false, /*ForEndCall=*/false,
+ /*DeviceAddrCB=*/nullptr, DynamicMapEntriesCB));
+
+ EXPECT_TRUE(DynamicCBWasCalled);
+ EXPECT_EQ(Info.NumberOfPtrs, 1U);
+ EXPECT_TRUE(Info.isValid());
+
+ auto expectDynamicAlloca = [](Value *V, Type *AllocatedTy) {
+ auto *AI = dyn_cast<AllocaInst>(V);
+ EXPECT_NE(AI, nullptr);
+ if (!AI)
+ return AI;
+ EXPECT_EQ(AI->getAllocatedType(), AllocatedTy);
+ auto *Size = dyn_cast<ConstantInt>(AI->getArraySize());
+ EXPECT_NE(Size, nullptr);
+ if (!Size)
+ return AI;
+ EXPECT_EQ(Size->getZExtValue(), 3U);
+ return AI;
+ };
+
+ AllocaInst *BasePtrsAlloca =
+ expectDynamicAlloca(Info.RTArgs.BasePointersArray, Builder.getPtrTy());
+ ASSERT_NE(BasePtrsAlloca, nullptr);
+ EXPECT_EQ(RTArgs.BasePointersArray->stripPointerCasts(), BasePtrsAlloca);
+ expectDynamicAlloca(Info.RTArgs.PointersArray, Builder.getPtrTy());
+ expectDynamicAlloca(Info.RTArgs.SizesArray, Builder.getInt64Ty());
+ AllocaInst *MapTypesAlloca =
+ expectDynamicAlloca(Info.RTArgs.MapTypesArray, Builder.getInt64Ty());
+ ASSERT_NE(MapTypesAlloca, nullptr);
+ expectDynamicAlloca(Info.RTArgs.MapNamesArray, Builder.getPtrTy());
+ expectDynamicAlloca(Info.RTArgs.MappersArray, Builder.getPtrTy());
+
+ SmallVector<uint64_t, 4> MapTypeStoreValues;
+ SmallVector<uint64_t, 4> MapTypeStoreIndices;
+ for (Instruction &I : instructions(F)) {
+ auto *SI = dyn_cast<StoreInst>(&I);
+ if (!SI)
+ continue;
+ auto *GEP = dyn_cast<GetElementPtrInst>(SI->getPointerOperand());
+ if (!GEP || GEP->getPointerOperand()->stripPointerCasts() != MapTypesAlloca)
+ continue;
+ auto *StoredValue = dyn_cast<ConstantInt>(SI->getValueOperand());
+ ASSERT_NE(StoredValue, nullptr);
+ MapTypeStoreValues.push_back(StoredValue->getZExtValue());
+ Value *IndexValue = *GEP->idx_begin();
+ auto *Index = dyn_cast<ConstantInt>(IndexValue);
+ ASSERT_NE(Index, nullptr);
+ MapTypeStoreIndices.push_back(Index->getZExtValue());
+ }
+
+ EXPECT_THAT(
+ MapTypeStoreValues,
+ testing::UnorderedElementsAre(
+ static_cast<uint64_t>(omp::OpenMPOffloadMappingFlags::OMP_MAP_TO),
+ static_cast<uint64_t>(omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM),
+ static_cast<uint64_t>(ToFromMapType)));
+ EXPECT_THAT(MapTypeStoreIndices, testing::UnorderedElementsAre(0, 1, 2));
+
+ Builder.restoreIP(OMPBuilder.Builder.saveIP());
+ Builder.CreateRetVoid();
+ EXPECT_FALSE(verifyModule(*M, &errs()));
+}
+
TEST_F(OpenMPIRBuilderTest, OffloadEntriesInfoManager) {
OpenMPIRBuilder OMPBuilder(*M);
OMPBuilder.setConfig(
diff --git a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
index d35e8612e158b..5d053d7c32340 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
@@ -493,14 +493,9 @@ static LogicalResult checkImplementationStatus(Operation &op) {
if (totalBits > 128)
result = todo("compare for complex types wider than 128 bits");
})
- .Case<omp::TargetEnterDataOp, omp::TargetExitDataOp>([&](auto op) {
- checkDepend(op, result);
- checkMap(op, result);
- })
- .Case([&](omp::TargetUpdateOp op) {
- checkDepend(op, result);
- checkMap(op, result);
- })
+ .Case<omp::TargetEnterDataOp, omp::TargetExitDataOp>(
+ [&](auto op) { checkDepend(op, result); })
+ .Case([&](omp::TargetUpdateOp op) { checkDepend(op, result); })
.Case([&](omp::TargetOp op) {
checkAllocate(op, result);
checkBare(op, result);
@@ -508,7 +503,7 @@ static LogicalResult checkImplementationStatus(Operation &op) {
checkMap(op, result);
checkThreadLimit(op, result);
})
- .Case([&](omp::TargetDataOp op) { checkMap(op, result); })
+ .Case([&](omp::TargetDataOp) {})
.Case([&](omp::DeclareMapperInfoOp op) { checkMap(op, result); })
.Default([](Operation &) {
// Assume all clauses for an operation can be translated unless they are
@@ -6757,6 +6752,7 @@ convertOmpTargetData(Operation *op, llvm::IRBuilderBase &builder,
llvm::Value *ifCond = nullptr;
llvm::Value *deviceID = builder.getInt64(llvm::omp::OMP_DEVICEID_UNDEF);
SmallVector<Value> mapVars;
+ SmallVector<Value> mapIterated;
SmallVector<Value> useDevicePtrVars;
SmallVector<Value> useDeviceAddrVars;
llvm::omp::RuntimeFunction RTLFn;
@@ -6789,6 +6785,7 @@ convertOmpTargetData(Operation *op, llvm::IRBuilderBase &builder,
deviceID = getDeviceID(devId);
mapVars = dataOp.getMapVars();
+ mapIterated = dataOp.getMapIterated();
useDevicePtrVars = dataOp.getUseDevicePtrVars();
useDeviceAddrVars = dataOp.getUseDeviceAddrVars();
return success();
@@ -6808,6 +6805,7 @@ convertOmpTargetData(Operation *op, llvm::IRBuilderBase &builder,
? llvm::omp::OMPRTL___tgt_target_data_begin_nowait_mapper
: llvm::omp::OMPRTL___tgt_target_data_begin_mapper;
mapVars = enterDataOp.getMapVars();
+ mapIterated = enterDataOp.getMapIterated();
info.HasNoWait = enterDataOp.getNowait();
return success();
})
@@ -6825,6 +6823,7 @@ convertOmpTargetData(Operation *op, llvm::IRBuilderBase &builder,
? llvm::omp::OMPRTL___tgt_target_data_end_nowait_mapper
: llvm::omp::OMPRTL___tgt_target_data_end_mapper;
mapVars = exitDataOp.getMapVars();
+ mapIterated = exitDataOp.getMapIterated();
info.HasNoWait = exitDataOp.getNowait();
return success();
})
@@ -6843,6 +6842,7 @@ convertOmpTargetData(Operation *op, llvm::IRBuilderBase &builder,
? llvm::omp::OMPRTL___tgt_target_data_update_nowait_mapper
: llvm::omp::OMPRTL___tgt_target_data_update_mapper;
mapVars = updateDataOp.getMapVars();
+ mapIterated = updateDataOp.getMapIterated();
info.HasNoWait = updateDataOp.getNowait();
return success();
})
@@ -6859,15 +6859,145 @@ convertOmpTargetData(Operation *op, llvm::IRBuilderBase &builder,
collectMapDataFromMapOperands(mapData, mapVars, moduleTranslation, DL,
builder, useDevicePtrVars, useDeviceAddrVars);
+ llvm::SmallVector<IteratorInfo, 2> iterInfos;
+ for (Value iter : mapIterated) {
+ auto itersOp = iter.getDefiningOp<omp::IteratorOp>();
+ assert(itersOp && "map_iterated value must be defined by omp.iterator");
+ auto yield =
+ dyn_cast<omp::YieldOp>(itersOp.getRegion().front().getTerminator());
+ assert(yield && yield.getResults().size() == 1 &&
+ "expect omp.yield in iterator region to have one result");
+ auto mapInfoOp = yield.getResults()[0].getDefiningOp<omp::MapInfoOp>();
+ assert(mapInfoOp && "expect iterator to yield omp.map.info");
+
+ if (!mapInfoOp.getMembers().empty()) {
+ mapInfoOp.emitError()
+ << "not yet implemented: map/motion clause with iterator modifier "
+ "that expands to member maps";
+ return failure();
+ }
+
+ iterInfos.emplace_back(itersOp, moduleTranslation, builder);
+ }
+
// Fill up the arrays with all the mapped variables.
MapInfosTy combinedInfo;
auto genMapInfoCB = [&](InsertPointTy codeGenIP) -> MapInfosTy & {
builder.restoreIP(codeGenIP);
genMapInfos(builder, moduleTranslation, DL, combinedInfo, mapData,
targetDirective);
+ if (!iterInfos.empty()) {
+ info.TotalMapCount = builder.getInt64(combinedInfo.BasePointers.size());
+ for (IteratorInfo &iterInfo : iterInfos)
+ info.TotalMapCount =
+ builder.CreateAdd(info.TotalMapCount, iterInfo.getTotalTrips());
+ }
return combinedInfo;
};
+ auto dynMapEntriesCB = [&](InsertPointTy codeGenIP,
+ llvm::OpenMPIRBuilder::TargetDataRTArgs &rtArgs,
+ unsigned staticCount) -> llvm::Error {
+ builder.restoreIP(codeGenIP);
+ llvm::Value *offset = builder.getInt64(staticCount);
+ llvm::Error dynError = llvm::Error::success();
+
+ auto mapTypeValue =
+ [&](llvm::omp::OpenMPOffloadMappingFlags flags) -> llvm::Value * {
+ return builder.getInt64(
+ static_cast<
+ std::underlying_type_t<llvm::omp::OpenMPOffloadMappingFlags>>(
+ flags));
+ };
+ auto endMapTypeValue =
+ [&](llvm::omp::OpenMPOffloadMappingFlags flags) -> llvm::Value * {
+ uint64_t mapping = static_cast<
+ std::underlying_type_t<llvm::omp::OpenMPOffloadMappingFlags>>(flags);
+ mapping &= ~static_cast<
+ std::underlying_type_t<llvm::omp::OpenMPOffloadMappingFlags>>(
+ llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_PRESENT);
+ return builder.getInt64(mapping);
+ };
+
+ for (auto [i, iterInfo] : llvm::enumerate(iterInfos)) {
+ auto itersOp = mapIterated[i].getDefiningOp<omp::IteratorOp>();
+ if (failed(fillIteratorLoop(
+ itersOp, builder, moduleTranslation, iterInfo, "map_iterator",
+ [&](llvm::Value *linearIV, omp::YieldOp yield) {
+ if (dynError)
+ return;
+
+ Value yieldedMap = yield.getResults()[0];
+ SmallVector<Value> iterMapVars{yieldedMap};
+ MapInfoData iterMapData;
+ collectMapDataFromMapOperands(iterMapData, iterMapVars,
+ moduleTranslation, DL, builder);
+
+ MapInfosTy iterCombinedInfo;
+ genMapInfos(builder, moduleTranslation, DL, iterCombinedInfo,
+ iterMapData, targetDirective);
+
+ if (!iterCombinedInfo.NonContigInfo.Offsets.empty()) {
+ yield.emitError()
+ << "not yet implemented: map/motion clause with iterator "
+ "modifier and non-contiguous map bounds";
+ dynError = llvm::make_error<PreviouslyReportedError>();
+ return;
+ }
+ if (iterCombinedInfo.BasePointers.size() != 1) {
+ yield.emitError()
+ << "not yet implemented: map/motion clause with iterator "
+ "modifier that expands to multiple map entries";
+ dynError = llvm::make_error<PreviouslyReportedError>();
+ return;
+ }
+
+ llvm::Value *mapperFunc = nullptr;
+ if (iterCombinedInfo.Mappers[0]) {
+ llvm::Function *mapperFn = nullptr;
+ {
+ llvm::IRBuilderBase::InsertPointGuard guard(builder);
+ llvm::Expected<llvm::Function *> mapper =
+ getOrCreateUserDefinedMapperFunc(
+ iterCombinedInfo.Mappers[0], builder,
+ moduleTranslation, targetDirective);
+ if (!mapper) {
+ dynError = mapper.takeError();
+ return;
+ }
+ mapperFn = *mapper;
+ }
+ mapperFunc =
+ builder.CreatePointerCast(mapperFn, builder.getPtrTy());
+ }
+
+ llvm::Value *idx = builder.CreateAdd(offset, linearIV);
+ llvm::Value *mapName = iterCombinedInfo.Names.empty()
+ ? nullptr
+ : iterCombinedInfo.Names[0];
+ ompBuilder->emitOffloadingArraysMapEntry(
+ builder, rtArgs, info, idx,
+ iterCombinedInfo.BasePointers[0],
+ iterCombinedInfo.Pointers[0], iterCombinedInfo.Sizes[0],
+ mapTypeValue(iterCombinedInfo.Types[0]),
+ endMapTypeValue(iterCombinedInfo.Types[0]), mapperFunc,
+ mapName);
+ }))) {
+ if (dynError)
+ return dynError;
+ return llvm::make_error<PreviouslyReportedError>();
+ }
+ if (dynError)
+ return dynError;
+
+ offset = builder.CreateAdd(offset, iterInfo.getTotalTrips());
+ }
+
+ ompBuilder->updateToLocation(
+ llvm::OpenMPIRBuilder::LocationDescription(builder));
+ return llvm::Error::success();
+ };
+
// Define a lambda to apply mappings between use_device_addr and
// use_device_ptr base pointers, and their associated block arguments.
auto mapUseDevice =
@@ -6975,12 +7105,27 @@ convertOmpTargetData(Operation *op, llvm::IRBuilderBase &builder,
llvm::OpenMPIRBuilder::InsertPointTy allocaIP =
findAllocInsertPoints(builder, moduleTranslation, &deallocBlocks);
llvm::OpenMPIRBuilder::InsertPointOrErrorTy afterIP = [&]() {
- if (isa<omp::TargetDataOp>(op))
+ if (isa<omp::TargetDataOp>(op)) {
+ if (!mapIterated.empty())
+ return ompBuilder->createTargetData(
+ ompLoc, allocaIP, builder.saveIP(), deallocBlocks, deviceID, ifCond,
+ info, genMapInfoCB, customMapperCB,
+ /*MapperFunc=*/nullptr, bodyGenCB,
+ /*DeviceAddrCB=*/nullptr,
+ /*SrcLocInfo=*/nullptr, dynMapEntriesCB);
return ompBuilder->createTargetData(ompLoc, allocaIP, builder.saveIP(),
deallocBlocks, deviceID, ifCond, info,
genMapInfoCB, customMapperCB,
/*MapperFunc=*/nullptr, bodyGenCB,
/*DeviceAddrCB=*/nullptr);
+ }
+ if (!mapIterated.empty())
+ return ompBuilder->createTargetData(
+ ompLoc, allocaIP, builder.saveIP(), deallocBlocks, deviceID, ifCond,
+ info, genMapInfoCB, customMapperCB, &RTLFn,
+ /*BodyGenCB=*/nullptr,
+ /*DeviceAddrCB=*/nullptr,
+ /*SrcLocInfo=*/nullptr, dynMapEntriesCB);
return ompBuilder->createTargetData(ompLoc, allocaIP, builder.saveIP(),
deallocBlocks, deviceID, ifCond, info,
genMapInfoCB, customMapperCB, &RTLFn);
diff --git a/mlir/test/Target/LLVMIR/openmp-iterator.mlir b/mlir/test/Target/LLVMIR/openmp-iterator.mlir
index 50afb68c4ce99..59aee4165bb74 100644
--- a/mlir/test/Target/LLVMIR/openmp-iterator.mlir
+++ b/mlir/test/Target/LLVMIR/openmp-iterator.mlir
@@ -478,6 +478,174 @@ module attributes {omp.is_target_device = false, omp.target_triples = ["amdgcn-a
}
llvm.return
}
+
+ omp.declare_mapper @simple_mapper : !llvm.struct<"SimpleMapperTy", (i32)> {
+ ^bb0(%arg0: !llvm.ptr):
+ %field = llvm.getelementptr %arg0[0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"SimpleMapperTy", (i32)>
+ %map = omp.map.info var_ptr(%field : !llvm.ptr, i32)
+ map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = "field"}
+ omp.declare_mapper.info map_entries(%map : !llvm.ptr)
+ }
+
+ // ------------------------------------------------------------------
+ // Map/motion clause with iterator modifier
+ // ------------------------------------------------------------------
+
+ llvm.func @target_update_map_iterator(%arr: !llvm.ptr) {
+ %c0 = llvm.mlir.constant(0 : i64) : i64
+ %c10 = llvm.mlir.constant(10 : i64) : i64
+ %c1 = llvm.mlir.constant(1 : i64) : i64
+
+ %it = omp.iterator(%iv: i64) = (%c0 to %c10 step %c1) {
+ %elem = llvm.getelementptr %arr[%iv] : (!llvm.ptr, i64) -> !llvm.ptr, i32
+ %map = omp.map.info var_ptr(%elem : !llvm.ptr, i32)
+ map_clauses(to) capture(ByRef) -> !llvm.ptr {name = ""}
+ omp.yield(%map : !llvm.ptr)
+ } -> !omp.iterated<!llvm.ptr>
+
+ omp.target_update map_iterated(%it : !omp.iterated<!llvm.ptr>)
+ llvm.return
+ }
+
+ llvm.func @target_update_multiple_map_iterators(%a: !llvm.ptr, %b: !llvm.ptr) {
+ %c0 = llvm.mlir.constant(0 : i64) : i64
+ %c1 = llvm.mlir.constant(1 : i64) : i64
+ %c2 = llvm.mlir.constant(2 : i64) : i64
+
+ %ita = omp.iterator(%iv: i64) = (%c0 to %c2 step %c1) {
+ %elem = llvm.getelementptr %a[%iv] : (!llvm.ptr, i64) -> !llvm.ptr, i32
+ %map = omp.map.info var_ptr(%elem : !llvm.ptr, i32)
+ map_clauses(to) capture(ByRef) -> !llvm.ptr {name = ""}
+ omp.yield(%map : !llvm.ptr)
+ } -> !omp.iterated<!llvm.ptr>
+
+ %itb = omp.iterator(%iv: i64) = (%c0 to %c1 step %c1) {
+ %elem = llvm.getelementptr %b[%iv] : (!llvm.ptr, i64) -> !llvm.ptr, i64
+ %map = omp.map.info var_ptr(%elem : !llvm.ptr, i64)
+ map_clauses(from) capture(ByRef) -> !llvm.ptr {name = ""}
+ omp.yield(%map : !llvm.ptr)
+ } -> !omp.iterated<!llvm.ptr>
+
+ omp.target_update map_iterated(%ita, %itb : !omp.iterated<!llvm.ptr>, !omp.iterated<!llvm.ptr>)
+ llvm.return
+ }
+
+ llvm.func @target_enter_data_map_iterator_mixed(%arr: !llvm.ptr, %scalar: !llvm.ptr) {
+ %c0 = llvm.mlir.constant(0 : i64) : i64
+ %c10 = llvm.mlir.constant(10 : i64) : i64
+ %c1 = llvm.mlir.constant(1 : i64) : i64
+
+ %static_map = omp.map.info var_ptr(%scalar : !llvm.ptr, f64)
+ map_clauses(to) capture(ByRef) -> !llvm.ptr {name = "scalar"}
+
+ %it = omp.iterator(%iv: i64) = (%c0 to %c10 step %c1) {
+ %elem = llvm.getelementptr %arr[%iv] : (!llvm.ptr, i64) -> !llvm.ptr, i32
+ %map = omp.map.info var_ptr(%elem : !llvm.ptr, i32)
+ map_clauses(to) capture(ByRef) -> !llvm.ptr {name = ""}
+ omp.yield(%map : !llvm.ptr)
+ } -> !omp.iterated<!llvm.ptr>
+
+ omp.target_enter_data map_entries(%static_map : !llvm.ptr) map_iterated(%it : !omp.iterated<!llvm.ptr>) {}
+ llvm.return
+ }
+
+ llvm.func @target_exit_data_map_iterator(%arr: !llvm.ptr) {
+ %c0 = llvm.mlir.constant(0 : i64) : i64
+ %c5 = llvm.mlir.constant(5 : i64) : i64
+ %c1 = llvm.mlir.constant(1 : i64) : i64
+
+ %it = omp.iterator(%iv: i64) = (%c0 to %c5 step %c1) {
+ %elem = llvm.getelementptr %arr[%iv] : (!llvm.ptr, i64) -> !llvm.ptr, i32
+ %map = omp.map.info var_ptr(%elem : !llvm.ptr, i32)
+ map_clauses(from) capture(ByRef) -> !llvm.ptr {name = ""}
+ omp.yield(%map : !llvm.ptr)
+ } -> !omp.iterated<!llvm.ptr>
+
+ omp.target_exit_data map_iterated(%it : !omp.iterated<!llvm.ptr>) {}
+ llvm.return
+ }
+
+ llvm.func @target_data_map_iterator(%arr: !llvm.ptr) {
+ %c0 = llvm.mlir.constant(0 : i64) : i64
+ %c2 = llvm.mlir.constant(2 : i64) : i64
+ %c1 = llvm.mlir.constant(1 : i64) : i64
+
+ %it = omp.iterator(%iv: i64) = (%c0 to %c2 step %c1) {
+ %elem = llvm.getelementptr %arr[%iv] : (!llvm.ptr, i64) -> !llvm.ptr, i32
+ %map = omp.map.info var_ptr(%elem : !llvm.ptr, i32)
+ map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = ""}
+ omp.yield(%map : !llvm.ptr)
+ } -> !omp.iterated<!llvm.ptr>
+
+ omp.target_data map_iterated(%it : !omp.iterated<!llvm.ptr>) {
+ omp.terminator
+ }
+ llvm.return
+ }
+
+ llvm.func @target_data_if_map_iterator_dynamic(
+ %arr: !llvm.ptr, %lb: i64, %ub: i64, %step: i64, %cond: i1) {
+ %it = omp.iterator(%iv: i64) = (%lb to %ub step %step) {
+ %elem = llvm.getelementptr %arr[%iv] : (!llvm.ptr, i64) -> !llvm.ptr, i32
+ %map = omp.map.info var_ptr(%elem : !llvm.ptr, i32)
+ map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = ""}
+ omp.yield(%map : !llvm.ptr)
+ } -> !omp.iterated<!llvm.ptr>
+
+ omp.target_data if(%cond) map_iterated(%it : !omp.iterated<!llvm.ptr>) {
+ omp.terminator
+ }
+ llvm.return
+ }
+
+ llvm.func @target_enter_data_map_iterator_dynamic(
+ %arr: !llvm.ptr, %lb: i64, %ub: i64, %step: i64) {
+ %it = omp.iterator(%iv: i64) = (%lb to %ub step %step) {
+ %elem = llvm.getelementptr %arr[%iv] : (!llvm.ptr, i64) -> !llvm.ptr, i32
+ %map = omp.map.info var_ptr(%elem : !llvm.ptr, i32)
+ map_clauses(to) capture(ByRef) -> !llvm.ptr {name = ""}
+ omp.yield(%map : !llvm.ptr)
+ } -> !omp.iterated<!llvm.ptr>
+
+ omp.target_enter_data map_iterated(%it : !omp.iterated<!llvm.ptr>) {}
+ llvm.return
+ }
+
+ llvm.func @target_enter_data_map_iterator_2d(%arr: !llvm.ptr) {
+ %c0 = llvm.mlir.constant(0 : i64) : i64
+ %c1 = llvm.mlir.constant(1 : i64) : i64
+ %c2 = llvm.mlir.constant(2 : i64) : i64
+ %c3 = llvm.mlir.constant(3 : i64) : i64
+
+ %it = omp.iterator(%i: i64, %j: i64) =
+ (%c0 to %c1 step %c1, %c0 to %c2 step %c1) {
+ %row = llvm.mul %i, %c3 : i64
+ %linear = llvm.add %row, %j : i64
+ %elem = llvm.getelementptr %arr[%linear] : (!llvm.ptr, i64) -> !llvm.ptr, i32
+ %map = omp.map.info var_ptr(%elem : !llvm.ptr, i32)
+ map_clauses(to) capture(ByRef) -> !llvm.ptr {name = ""}
+ omp.yield(%map : !llvm.ptr)
+ } -> !omp.iterated<!llvm.ptr>
+
+ omp.target_enter_data map_iterated(%it : !omp.iterated<!llvm.ptr>) {}
+ llvm.return
+ }
+
+ llvm.func @target_enter_data_map_iterator_mapper(%arr: !llvm.ptr) {
+ %c0 = llvm.mlir.constant(0 : i64) : i64
+ %c2 = llvm.mlir.constant(2 : i64) : i64
+ %c1 = llvm.mlir.constant(1 : i64) : i64
+
+ %it = omp.iterator(%iv: i64) = (%c0 to %c2 step %c1) {
+ %elem = llvm.getelementptr %arr[%iv] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.struct<"SimpleMapperTy", (i32)>
+ %map = omp.map.info var_ptr(%elem : !llvm.ptr, !llvm.struct<"SimpleMapperTy", (i32)>)
+ map_clauses(to) capture(ByRef) mapper(@simple_mapper) -> !llvm.ptr {name = ""}
+ omp.yield(%map : !llvm.ptr)
+ } -> !omp.iterated<!llvm.ptr>
+
+ omp.target_enter_data map_iterated(%it : !omp.iterated<!llvm.ptr>) {}
+ llvm.return
+ }
}
// TARGET-LABEL: define void @omp_target_depend_iterator
@@ -513,3 +681,143 @@ module attributes {omp.is_target_device = false, omp.target_triples = ["amdgcn-a
// TARGET: call void @.omp_target_task_proxy_func
// TARGET: call void @__kmpc_omp_task_complete_if0
// TARGET: tail call void @free(ptr %[[DEP_ARR]])
+
+// target_update lowers iterated motion entries into dynamic offload arrays.
+// TARGET-LABEL: define void @target_update_map_iterator
+// TARGET-SAME: (ptr %[[ARR:[0-9]+]])
+// TARGET-DAG: %[[BASEPTRS:[^ ]*offload_baseptrs]] = alloca ptr, i64 11
+// TARGET-DAG: %[[PTRS:[^ ]*offload_ptrs]] = alloca ptr, i64 11
+// TARGET-DAG: %[[SIZES:[^ ]*offload_sizes]] = alloca i64, i64 11
+// TARGET-DAG: %[[TYPES:[^ ]*offload_maptypes]] = alloca i64, i64 11
+// TARGET: omp_map_iterator.body{{.*}}:
+// TARGET: %[[ELEM:.*]] = getelementptr i32, ptr %[[ARR]], i64 %{{.*}}
+// TARGET: %[[IDX:.*]] = add i64 0, %{{.*}}
+// TARGET: %[[BP_SLOT:.*]] = getelementptr inbounds ptr, ptr %[[BASEPTRS]], i64 %[[IDX]]
+// TARGET: store ptr %[[ELEM]], ptr %[[BP_SLOT]]
+// TARGET: %[[P_SLOT:.*]] = getelementptr inbounds ptr, ptr %[[PTRS]], i64 %[[IDX]]
+// TARGET: store ptr %[[ELEM]], ptr %[[P_SLOT]]
+// TARGET: %[[SIZE_SLOT:.*]] = getelementptr inbounds i64, ptr %[[SIZES]], i64 %[[IDX]]
+// TARGET: store i64 4, ptr %[[SIZE_SLOT]]
+// TARGET: %[[TYPE_SLOT:.*]] = getelementptr inbounds i64, ptr %[[TYPES]], i64 %[[IDX]]
+// TARGET: store i64 1, ptr %[[TYPE_SLOT]]
+// TARGET: call void @__tgt_target_data_update_mapper(ptr @{{.*}}, i64 -1, i32 11, ptr %[[BASEPTRS]], ptr %[[PTRS]], ptr %[[SIZES]], ptr %[[TYPES]],
+
+// Multiple map_iterated operands are appended in operand order into one set of
+// dynamic offload arrays.
+// TARGET-LABEL: define void @target_update_multiple_map_iterators
+// TARGET-SAME: (ptr %[[ARRA:[0-9]+]], ptr %[[ARRB:[0-9]+]])
+// TARGET-DAG: %[[BASEPTRSM:[^ ]*offload_baseptrs]] = alloca ptr, i64 5
+// TARGET-DAG: %[[PTRSM:[^ ]*offload_ptrs]] = alloca ptr, i64 5
+// TARGET-DAG: %[[SIZESM:[^ ]*offload_sizes]] = alloca i64, i64 5
+// TARGET-DAG: %[[TYPESM:[^ ]*offload_maptypes]] = alloca i64, i64 5
+// TARGET: omp_map_iterator.body{{.*}}:
+// TARGET: %[[ELEMA:.*]] = getelementptr i32, ptr %[[ARRA]], i64 %{{.*}}
+// TARGET: %[[IDXA:.*]] = add i64 0, %{{.*}}
+// TARGET: %[[BPSLOTA:.*]] = getelementptr inbounds ptr, ptr %[[BASEPTRSM]], i64 %[[IDXA]]
+// TARGET: store ptr %[[ELEMA]], ptr %[[BPSLOTA]]
+// TARGET: %[[PSLOTA:.*]] = getelementptr inbounds ptr, ptr %[[PTRSM]], i64 %[[IDXA]]
+// TARGET: store ptr %[[ELEMA]], ptr %[[PSLOTA]]
+// TARGET: %[[SIZESLOTA:.*]] = getelementptr inbounds i64, ptr %[[SIZESM]], i64 %[[IDXA]]
+// TARGET: store i64 4, ptr %[[SIZESLOTA]]
+// TARGET: %[[TYPESLOTA:.*]] = getelementptr inbounds i64, ptr %[[TYPESM]], i64 %[[IDXA]]
+// TARGET: store i64 1, ptr %[[TYPESLOTA]]
+// TARGET: omp_map_iterator.body{{.*}}:
+// TARGET: %[[ELEMB:.*]] = getelementptr i64, ptr %[[ARRB]], i64 %{{.*}}
+// TARGET: %[[IDXB:.*]] = add i64 3, %{{.*}}
+// TARGET: %[[BPSLOTB:.*]] = getelementptr inbounds ptr, ptr %[[BASEPTRSM]], i64 %[[IDXB]]
+// TARGET: store ptr %[[ELEMB]], ptr %[[BPSLOTB]]
+// TARGET: %[[PSLOTB:.*]] = getelementptr inbounds ptr, ptr %[[PTRSM]], i64 %[[IDXB]]
+// TARGET: store ptr %[[ELEMB]], ptr %[[PSLOTB]]
+// TARGET: %[[SIZESLOTB:.*]] = getelementptr inbounds i64, ptr %[[SIZESM]], i64 %[[IDXB]]
+// TARGET: store i64 8, ptr %[[SIZESLOTB]]
+// TARGET: %[[TYPESLOTB:.*]] = getelementptr inbounds i64, ptr %[[TYPESM]], i64 %[[IDXB]]
+// TARGET: store i64 2, ptr %[[TYPESLOTB]]
+// TARGET: call void @__tgt_target_data_update_mapper(ptr @{{.*}}, i64 -1, i32 5, ptr %[[BASEPTRSM]], ptr %[[PTRSM]], ptr %[[SIZESM]], ptr %[[TYPESM]],
+
+// Static entries are stored first, followed by the iterator-expanded entries.
+// TARGET-LABEL: define void @target_enter_data_map_iterator_mixed
+// TARGET-SAME: (ptr %[[ARR2:[0-9]+]], ptr %[[SCALAR:[0-9]+]])
+// TARGET-DAG: %[[BASEPTRS2:[^ ]*offload_baseptrs]] = alloca ptr, i64 12
+// TARGET: %[[STATIC_BP:.*]] = getelementptr inbounds ptr, ptr %[[BASEPTRS2]], i64 0
+// TARGET: store ptr %[[SCALAR]], ptr %[[STATIC_BP]]
+// TARGET: omp_map_iterator.body:
+// TARGET: %[[ELEM2:.*]] = getelementptr i32, ptr %[[ARR2]], i64 %{{.*}}
+// TARGET: %[[IDX2:.*]] = add i64 1, %{{.*}}
+// TARGET: %[[ITER_BP:.*]] = getelementptr inbounds ptr, ptr %[[BASEPTRS2]], i64 %[[IDX2]]
+// TARGET: store ptr %[[ELEM2]], ptr %[[ITER_BP]]
+// TARGET: call void @__tgt_target_data_begin_mapper(ptr @{{.*}}, i64 -1, i32 12, ptr %[[BASEPTRS2]],
+
+// target_exit_data preserves the iterator-expanded FROM map type.
+// TARGET-LABEL: define void @target_exit_data_map_iterator
+// TARGET-SAME: (ptr %[[ARR3:[0-9]+]])
+// TARGET-DAG: %[[BASEPTRS3:[^ ]*offload_baseptrs]] = alloca ptr, i64 6
+// TARGET-DAG: %[[TYPES3:[^ ]*offload_maptypes]] = alloca i64, i64 6
+// TARGET: omp_map_iterator.body:
+// TARGET: %[[IDX3:.*]] = add i64 0, %omp_map_iterator.iv
+// TARGET: %[[TYPE_SLOT3:.*]] = getelementptr inbounds i64, ptr %[[TYPES3]], i64 %[[IDX3]]
+// TARGET: store i64 2, ptr %[[TYPE_SLOT3]]
+// TARGET: call void @__tgt_target_data_end_mapper(ptr @{{.*}}, i64 -1, i32 6, ptr %[[BASEPTRS3]],
+
+// target_data uses the same dynamic arrays for begin and end runtime calls.
+// TARGET-LABEL: define void @target_data_map_iterator
+// TARGET-SAME: (ptr %[[ARR4:[0-9]+]])
+// TARGET-DAG: %[[BASEPTRS4:[^ ]*offload_baseptrs]] = alloca ptr, i64 3
+// TARGET-DAG: %[[TYPES4:[^ ]*offload_maptypes]] = alloca i64, i64 3
+// TARGET-DAG: %[[ENDTYPES4:[^ ]*offload_maptypes_end]] = alloca i64, i64 3
+// TARGET: omp_map_iterator.body:
+// TARGET: store i64 3, ptr %{{.*}}
+// TARGET: store i64 3, ptr %{{.*}}
+// TARGET: call void @__tgt_target_data_begin_mapper(ptr @{{.*}}, i64 -1, i32 3, ptr %[[BASEPTRS4]]
+// TARGET: call void @__tgt_target_data_end_mapper(ptr @{{.*}}, i64 -1, i32 3, ptr %[[BASEPTRS4]], ptr %{{.*}}, ptr %{{.*}}, ptr %[[ENDTYPES4]]
+
+// target_data with an if clause hoists dynamic count and array allocas before
+// the begin/end control-flow split.
+// TARGET-LABEL: define void @target_data_if_map_iterator_dynamic
+// TARGET-SAME: (ptr %[[ARRIF:[0-9]+]], i64 %[[LBIF:[0-9]+]], i64 %[[UBIF:[0-9]+]], i64 %[[STEPIF:[0-9]+]], i1 %[[CONDIF:[0-9]+]])
+// TARGET: %[[DIFFIF:.*]] = sub i64 %[[UBIF]], %[[LBIF]]
+// TARGET: %[[DIVIF:.*]] = sdiv i64 %[[DIFFIF]], %[[STEPIF]]
+// TARGET: %[[TRIPSIF:.*]] = add i64 %[[DIVIF]], 1
+// TARGET: %[[TOTALIF:.*]] = add i64 0, %{{.*}}
+// TARGET: %[[BASEPTRSIF:[^ ]*offload_baseptrs]] = alloca ptr, i64 %[[TOTALIF]]
+// TARGET: br i1 %[[CONDIF]], label %omp_if.then
+// TARGET: call void @__tgt_target_data_begin_mapper(ptr @{{.*}}, i64 -1, i32 %{{.*}}, ptr %[[BASEPTRSIF]]
+// TARGET: call void @__tgt_target_data_end_mapper(ptr @{{.*}}, i64 -1, i32 %{{.*}}, ptr %[[BASEPTRSIF]]
+
+// Dynamic iterator bounds produce a runtime map count and VLA offload arrays.
+// TARGET-LABEL: define void @target_enter_data_map_iterator_dynamic
+// TARGET-SAME: (ptr %[[ARR5:[0-9]+]], i64 %[[LB:[0-9]+]], i64 %[[UB:[0-9]+]], i64 %[[STEP:[0-9]+]])
+// TARGET: %[[DIFF:.*]] = sub i64 %[[UB]], %[[LB]]
+// TARGET: %[[DIV:.*]] = sdiv i64 %[[DIFF]], %[[STEP]]
+// TARGET: %[[TRIPS:.*]] = add i64 %[[DIV]], 1
+// TARGET: %[[SCALED:.*]] = mul i64 1, %[[TRIPS]]
+// TARGET: %[[TOTAL:.*]] = add i64 0, %[[SCALED]]
+// TARGET-DAG: %[[BASEPTRS5:[^ ]*offload_baseptrs]] = alloca ptr, i64 %[[TOTAL]]
+// TARGET-DAG: %[[PTRS5:[^ ]*offload_ptrs]] = alloca ptr, i64 %[[TOTAL]]
+// TARGET: omp_map_iterator.body:
+// TARGET: getelementptr i32, ptr %[[ARR5]], i64 %{{.*}}
+// TARGET: %[[NPTRS:.*]] = trunc i64 %[[TOTAL]] to i32
+// TARGET: call void @__tgt_target_data_begin_mapper(ptr @{{.*}}, i64 -1, i32 %[[NPTRS]], ptr %[[BASEPTRS5]], ptr %[[PTRS5]],
+
+// Multidimensional iterators reconstruct physical IVs before filling the map
+// entry for each linearized iteration.
+// TARGET-LABEL: define void @target_enter_data_map_iterator_2d
+// TARGET-SAME: (ptr %[[ARR2D:[0-9]+]])
+// TARGET-DAG: %[[BASEPTRS2D:[^ ]*offload_baseptrs]] = alloca ptr, i64 6
+// TARGET-DAG: %[[PTRS2D:[^ ]*offload_ptrs]] = alloca ptr, i64 6
+// TARGET: omp_map_iterator.body:
+// TARGET: %[[REMJ:.*]] = urem i64 %{{.*}}, 3
+// TARGET: %[[DIVJ:.*]] = udiv i64 %{{.*}}, 3
+// TARGET: %[[REMI:.*]] = urem i64 %[[DIVJ]], 2
+// TARGET: %[[ROW:.*]] = mul i64 %{{.*}}, 3
+// TARGET: %[[LINEAR:.*]] = add i64 %[[ROW]], %{{.*}}
+// TARGET: %[[ELEM2D:.*]] = getelementptr i32, ptr %[[ARR2D]], i64 %[[LINEAR]]
+// TARGET: store ptr %[[ELEM2D]], ptr %{{.*}}
+// TARGET: call void @__tgt_target_data_begin_mapper(ptr @{{.*}}, i64 -1, i32 6, ptr %[[BASEPTRS2D]], ptr %[[PTRS2D]],
+
+// Iterated entries preserve explicit mapper IDs in the mapper array.
+// TARGET-LABEL: define void @target_enter_data_map_iterator_mapper
+// TARGET-DAG: %[[MAPPERS6:[^ ]*offload_mappers]] = alloca ptr, i64 3
+// TARGET: omp_map_iterator.body:
+// TARGET: %[[MAPPER_SLOT:.*]] = getelementptr inbounds ptr, ptr %[[MAPPERS6]], i64 %{{.*}}
+// TARGET: store ptr @.omp_mapper.simple_mapper, ptr %[[MAPPER_SLOT]]
+// TARGET: call void @__tgt_target_data_begin_mapper(ptr @{{.*}}, i64 -1, i32 3, ptr %{{.*}}, ptr %{{.*}}, ptr %{{.*}}, ptr %{{.*}}, ptr %{{.*}}, ptr %[[MAPPERS6]])
diff --git a/mlir/test/Target/LLVMIR/openmp-todo.mlir b/mlir/test/Target/LLVMIR/openmp-todo.mlir
index fa08590978f43..084625818f31b 100644
--- a/mlir/test/Target/LLVMIR/openmp-todo.mlir
+++ b/mlir/test/Target/LLVMIR/openmp-todo.mlir
@@ -496,54 +496,6 @@ llvm.func @wsloop_order(%lb : i32, %ub : i32, %step : i32) {
// -----
-llvm.func @target_enter_data_map_iterator(%addr : !llvm.ptr) {
- %c0 = llvm.mlir.constant(0 : i64) : i64
- %c10 = llvm.mlir.constant(10 : i64) : i64
- %c1 = llvm.mlir.constant(1 : i64) : i64
- %it = omp.iterator(%iv: i64) = (%c0 to %c10 step %c1) {
- %m = omp.map.info var_ptr(%addr : !llvm.ptr, i32) map_clauses(to) capture(ByRef) -> !llvm.ptr {name = ""}
- omp.yield(%m : !llvm.ptr)
- } -> !omp.iterated<!llvm.ptr>
- // expected-error at below {{not yet implemented: Unhandled clause map/motion clause with iterator modifier in omp.target_enter_data operation}}
- // expected-error at below {{LLVM Translation failed for operation: omp.target_enter_data}}
- omp.target_enter_data map_iterated(%it : !omp.iterated<!llvm.ptr>) {}
- llvm.return
-}
-
-// -----
-
-llvm.func @target_exit_data_map_iterator(%addr : !llvm.ptr) {
- %c0 = llvm.mlir.constant(0 : i64) : i64
- %c10 = llvm.mlir.constant(10 : i64) : i64
- %c1 = llvm.mlir.constant(1 : i64) : i64
- %it = omp.iterator(%iv: i64) = (%c0 to %c10 step %c1) {
- %m = omp.map.info var_ptr(%addr : !llvm.ptr, i32) map_clauses(from) capture(ByRef) -> !llvm.ptr {name = ""}
- omp.yield(%m : !llvm.ptr)
- } -> !omp.iterated<!llvm.ptr>
- // expected-error at below {{not yet implemented: Unhandled clause map/motion clause with iterator modifier in omp.target_exit_data operation}}
- // expected-error at below {{LLVM Translation failed for operation: omp.target_exit_data}}
- omp.target_exit_data map_iterated(%it : !omp.iterated<!llvm.ptr>) {}
- llvm.return
-}
-
-// -----
-
-llvm.func @target_update_map_iterator(%addr : !llvm.ptr) {
- %c0 = llvm.mlir.constant(0 : i64) : i64
- %c10 = llvm.mlir.constant(10 : i64) : i64
- %c1 = llvm.mlir.constant(1 : i64) : i64
- %it = omp.iterator(%iv: i64) = (%c0 to %c10 step %c1) {
- %m = omp.map.info var_ptr(%addr : !llvm.ptr, i32) map_clauses(to) capture(ByRef) -> !llvm.ptr {name = ""}
- omp.yield(%m : !llvm.ptr)
- } -> !omp.iterated<!llvm.ptr>
- // expected-error at below {{not yet implemented: Unhandled clause map/motion clause with iterator modifier in omp.target_update operation}}
- // expected-error at below {{LLVM Translation failed for operation: omp.target_update}}
- omp.target_update map_iterated(%it : !omp.iterated<!llvm.ptr>)
- llvm.return
-}
-
-// -----
-
llvm.func @target_map_iterated_unsupported(%addr : !llvm.ptr) {
%c0 = llvm.mlir.constant(0 : i64) : i64
%c10 = llvm.mlir.constant(10 : i64) : i64
@@ -563,22 +515,6 @@ llvm.func @target_map_iterated_unsupported(%addr : !llvm.ptr) {
// -----
-llvm.func @target_data_map_iterator(%addr : !llvm.ptr) {
- %c0 = llvm.mlir.constant(0 : i64) : i64
- %c10 = llvm.mlir.constant(10 : i64) : i64
- %c1 = llvm.mlir.constant(1 : i64) : i64
- %it = omp.iterator(%iv: i64) = (%c0 to %c10 step %c1) {
- %m = omp.map.info var_ptr(%addr : !llvm.ptr, i32) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = ""}
- omp.yield(%m : !llvm.ptr)
- } -> !omp.iterated<!llvm.ptr>
- // expected-error at below {{not yet implemented: Unhandled clause map/motion clause with iterator modifier in omp.target_data operation}}
- // expected-error at below {{LLVM Translation failed for operation: omp.target_data}}
- omp.target_data map_iterated(%it : !omp.iterated<!llvm.ptr>) {}
- llvm.return
-}
-
-// -----
-
module attributes {omp.target_triples = ["amdgcn-amd-amdhsa"]} {
omp.declare_mapper @mapper_with_iterator : !llvm.struct<"mapper_type", (i32)> {
^bb0(%arg: !llvm.ptr):
@@ -600,3 +536,21 @@ module attributes {omp.target_triples = ["amdgcn-amd-amdhsa"]} {
llvm.return
}
}
+
+// -----
+
+llvm.func @target_enter_data_map_iterator_members(%addr : !llvm.ptr) {
+ %c0 = llvm.mlir.constant(0 : i64) : i64
+ %c10 = llvm.mlir.constant(10 : i64) : i64
+ %c1 = llvm.mlir.constant(1 : i64) : i64
+ %it = omp.iterator(%iv: i64) = (%c0 to %c10 step %c1) {
+ %field = llvm.getelementptr %addr[0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"map_type", (i32)>
+ %field_map = omp.map.info var_ptr(%field : !llvm.ptr, i32) map_clauses(to) capture(ByRef) -> !llvm.ptr {name = ""}
+ // expected-error at below {{not yet implemented: map/motion clause with iterator modifier that expands to member maps}}
+ %map = omp.map.info var_ptr(%addr : !llvm.ptr, !llvm.struct<"map_type", (i32)>) map_clauses(to) capture(ByRef) members(%field_map : [0] : !llvm.ptr) -> !llvm.ptr {name = ""}
+ omp.yield(%map : !llvm.ptr)
+ } -> !omp.iterated<!llvm.ptr>
+ // expected-error at below {{LLVM Translation failed for operation: omp.target_enter_data}}
+ omp.target_enter_data map_iterated(%it : !omp.iterated<!llvm.ptr>) {}
+ llvm.return
+}
diff --git a/offload/test/offloading/fortran/map-motion-iterator.f90 b/offload/test/offloading/fortran/map-motion-iterator.f90
new file mode 100644
index 0000000000000..498d2cf355c20
--- /dev/null
+++ b/offload/test/offloading/fortran/map-motion-iterator.f90
@@ -0,0 +1,119 @@
+! Offloading test for iterator modifier on map and motion clauses.
+
+! REQUIRES: flang, amdgpu
+
+! RUN: %libomptarget-compile-fortran-run-and-check-generic
+
+program map_motion_iterator
+ implicit none
+ integer, parameter :: n = 8
+ integer :: a(n), b(n), c(n), d(n), e(n)
+ integer :: i, dyn_n, dyn_step
+ logical :: use_device
+
+ do i = 1, n
+ a(i) = i
+ end do
+ !$omp target enter data map(to: a)
+ !$omp target
+ do i = 2, n, 2
+ a(i) = 100 + i
+ end do
+ !$omp end target
+ do i = 2, n, 2
+ a(i) = -100
+ end do
+ !$omp target update from(iterator(i = 2:n:2): a(i))
+ !$omp target exit data map(delete: a)
+
+ ! CHECK: update from: 1 102 3 104 5 106 7 108
+ print *, "update from:", a
+
+ do i = 1, n
+ b(i) = i
+ end do
+ !$omp target enter data map(to: b)
+ do i = 2, n, 2
+ b(i) = 200 + i
+ end do
+ !$omp target update to(iterator(i = 2:n:2): b(i))
+ !$omp target
+ do i = 2, n, 2
+ b(i) = b(i) + 10
+ end do
+ !$omp end target
+ do i = 2, n, 2
+ b(i) = -100
+ end do
+ !$omp target update from(iterator(i = 2:n:2): b(i))
+ !$omp target exit data map(delete: b)
+
+ ! CHECK: update tofrom: 1 212 3 214 5 216 7 218
+ print *, "update tofrom:", b
+
+ do i = 1, n
+ c(i) = i
+ end do
+ !$omp target enter data map(to: c)
+ !$omp target
+ c(1) = 11
+ c(3) = 33
+ c(5) = 55
+ c(7) = 77
+ !$omp end target
+ do i = 1, n, 2
+ c(i) = -100
+ end do
+ !$omp target exit data map(iterator(i = 1:n:2), from: c(i))
+ !$omp target exit data map(delete: c)
+
+ ! CHECK: exit data: 11 2 33 4 55 6 77 8
+ print *, "exit data:", c
+
+ do i = 1, n
+ d(i) = i
+ end do
+ !$omp target data map(iterator(i = 1:n:2), tofrom: d(i))
+ !$omp target map(present, alloc: d(1))
+ d(1) = 21
+ !$omp end target
+ !$omp target map(present, alloc: d(3))
+ d(3) = 43
+ !$omp end target
+ !$omp target map(present, alloc: d(5))
+ d(5) = 65
+ !$omp end target
+ !$omp target map(present, alloc: d(7))
+ d(7) = 87
+ !$omp end target
+ !$omp end target data
+
+ ! CHECK: target data: 21 2 43 4 65 6 87 8
+ print *, "target data:", d
+
+ dyn_n = n
+ dyn_step = 2
+ use_device = .true.
+ do i = 1, n
+ e(i) = i
+ end do
+ !$omp target data if(use_device) &
+ !$omp& map(iterator(i = 1:dyn_n:dyn_step), tofrom: e(i))
+ !$omp target map(present, alloc: e(1))
+ e(1) = 31
+ !$omp end target
+ !$omp target map(present, alloc: e(3))
+ e(3) = 53
+ !$omp end target
+ !$omp target map(present, alloc: e(5))
+ e(5) = 75
+ !$omp end target
+ !$omp target map(present, alloc: e(7))
+ e(7) = 97
+ !$omp end target
+ !$omp end target data
+
+ ! CHECK: target data if: 31 2 53 4 75 6 97 8
+ print *, "target data if:", e
+
+end program map_motion_iterator
More information about the llvm-branch-commits
mailing list