[flang-commits] [flang] [llvm] [mlir] [flang][mlir][OpenMP] Support iterator modifier in declare mapper map clause (PR #215485)

Urvi Rav via flang-commits flang-commits at lists.llvm.org
Tue Sep 29 02:18:37 PDT 2026


================
@@ -2062,13 +2081,132 @@ bool ClauseProcessor::processMap(
       }
     }
 
-    if (iterator)
-      TODO(currentLocation,
-           "Support for iterator modifiers is not implemented yet");
     TodoLocators(currentLocation, objects);
 
-    processMapObjects(stmtCtx, clauseLocation,
-                      std::get<omp::ObjectList>(clause.t), mapTypeBits,
+    if (!iterator) {
+      processMapObjects(stmtCtx, clauseLocation, objects, mapTypeBits,
+                        parentMemberIndices, result.mapVars, *ptrMapObjects,
+                        mapperIdName, /*isMotionModifier=*/false, directive);
+      return;
+    }
+
+    llvm::SmallVector<IteratorRange> iteratorRanges;
+    llvm::SmallPtrSet<const Fortran::semantics::Symbol *, 4> ivSyms;
+    collectIteratorIVs(clause, converter, stmtCtx, iteratorRanges, ivSyms);
+
+    // Objects that reference an iterator induction variable are expanded at
+    // runtime via `omp.iterator`/`map_iterated`; the rest go through the
+    // regular static map-info path below.
+    omp::ObjectList staticObjects;
+    fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
+    for (const omp::Object &object : objects) {
+      if (!hasIteratorIVReference(object, ivSyms)) {
+        staticObjects.push_back(object);
+        continue;
+      }
+
+      if (isArraySectionSubscript(object))
+        TODO(currentLocation,
+             "Iterator modifier on an array section in a map clause is not "
+             "implemented yet");
+
+      // The per-iteration `omp.map.info` this produces lives inside the
+      // `omp.iterator` body and cannot be attached as a `members` operand
+      // of some other (parent) MapInfoOp built outside that region, since
+      // only the aggregated `!omp.iterated<T>` handle escapes the region.
+      // We still register the parent with `parentMemberIndices` (with no
+      // child attached) so `insertChildMapInfoIntoParent` synthesizes the
+      // usual partial/"storage" map for the parent object (e.g. the
+      // `declare mapper` association variable itself); the iterator-driven
+      // child map is emitted separately into `result.mapIterated`, mirroring
+      // how `map_vars`/`members` (static) and `map_iterated` (runtime
+      // expanded) already coexist as sibling operands on the owning op.
+      bool hasParentObj = object.sym()->owner().IsDerivedType();
+      mlir::Value baseAddr;
+      if (hasParentObj) {
+        omp::ObjectList objectList = gatherObjectsOf(object, semaCtx);
+        assert(!objectList.empty() &&
+               "could not find parent objects of derived type member");
+        if (isMemberOrParentAllocatableOrPointer(object, semaCtx))
+          TODO(currentLocation,
+               "Iterator modifier on this derived-type member in a map "
+               "clause is not implemented yet");
+
+        omp::Object baseObject = objectList[0];
+        parentMemberIndices.emplace(baseObject, OmpMapParentAndMemberData{});
+
+        // `objectList` includes an extra entry for the subscripted
+        // reference itself (e.g. [v, v%a, v%a(i)]) on top of one entry per
+        // derived-type level walked, so only a single record-field
+        // placement index means this is a single-level, non-nested member.
+        llvm::SmallVector<int64_t> memberIndices;
+        generateMemberPlacementIndices(object, memberIndices, semaCtx);
+        if (memberIndices.size() != 1)
+          TODO(currentLocation,
+               "Iterator modifier on a nested derived-type member in a map "
+               "clause is not implemented yet");
+
+        fir::factory::AddrAndBoundsInfo parentInfo =
+            Fortran::lower::getDataOperandBaseAddr(
+                converter, firOpBuilder, *baseObject.sym(), clauseLocation,
+                /*unwrapFirBox=*/false);
+        auto recordType = mlir::dyn_cast<fir::RecordType>(
+            fir::unwrapPassByRefType(parentInfo.addr.getType()));
+        if (!recordType)
+          TODO(currentLocation,
+               "Iterator modifier on this derived-type member in a map "
+               "clause is not implemented yet");
+
+        mlir::Type fieldTy = recordType.getType(memberIndices[0]);
+        fir::IntOrValue idxConst =
+            mlir::IntegerAttr::get(firOpBuilder.getI32Type(), memberIndices[0]);
+        baseAddr = fir::CoordinateOp::create(
+            firOpBuilder, clauseLocation, firOpBuilder.getRefType(fieldTy),
+            parentInfo.addr, llvm::SmallVector<fir::IntOrValue, 1>{idxConst});
+      } else {
+        fir::factory::AddrAndBoundsInfo info =
+            Fortran::lower::getDataOperandBaseAddr(
+                converter, firOpBuilder, *object.sym(), clauseLocation,
+                /*unwrapFirBox=*/false);
+        baseAddr = info.addr;
+      }
+      hlfir::Entity entity{baseAddr};
----------------
ravurvi20 wrote:

Added `hasExplicitNonDefaultLowerBound()` to detect an explicit non-default lower bound and added a `TODO` for this case before building the coordinate, so we don't silently generate an incorrect offset.

I also added a regression test in `map-iterator-nondefault-lower-bound.f90` covering `integer :: a(-2:2)` with `map(iterator(i=-2:2): x%a(i))`.


https://github.com/llvm/llvm-project/pull/215485


More information about the flang-commits mailing list