[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