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

via flang-commits flang-commits at lists.llvm.org
Fri Oct 23 00:14:56 PDT 2026


================
@@ -8597,9 +8629,73 @@ emitUserDefinedMapper(Operation *op, llvm::IRBuilderBase &builder,
     genMapInfos(builder, moduleTranslation, dl, combinedInfo, mapData,
                 targetDirective);
 
-    // Drop the mapping that is no longer necessary so that the same region
-    // can be processed multiple times.
-    moduleTranslation.forgetMapping(declMapperOp.getRegion());
+    // Components produced by an `iterator` modifier on the mapper's own map
+    // clause: their count is only known at runtime, so they are recorded as
+    // dynamic segments and pushed one at a time (via
+    // __tgt_push_mapper_component) from a generated loop, mirroring how the
+    // depend/affinity clauses already handle iterator-produced entries.
+    for (mlir::Value iterVal : declMapperInfoOp.getMapIterated()) {
+      auto itersOp = iterVal.getDefiningOp<mlir::omp::IteratorOp>();
+      assert(itersOp && "map_iterated value must be defined by omp.iterator");
+      // Lowering a scalar subscript (e.g. involving LEN_TRIM) can introduce
+      // control flow inside the iterator, so its `omp.yield` is not
+      // necessarily in the region's first block.
+      mlir::omp::YieldOp yieldOp = itersOp.getYieldOp();
+      assert(yieldOp && "expected exactly one omp.yield in the iterator body");
+      auto mapInfoOp =
+          yieldOp.getResults()[0].getDefiningOp<mlir::omp::MapInfoOp>();
+      assert(mapInfoOp && "expected an omp.map.info in the map_iterated body");
+
+      llvm::Value *sizeVal =
+          builder.getInt64(dl.getTypeSize(mapInfoOp.getVarPtrType()));
+      llvm::omp::OpenMPOffloadMappingFlags mapType =
+          convertClauseMapFlags(mapInfoOp.getMapType());
+      bool hasAttachPtr =
+          (mapType & llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_ATTACH) !=
+          llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_NONE;
+
+      IteratorInfo iterInfo(itersOp, moduleTranslation, builder);
+      llvm::Value *count = iterInfo.getTotalTrips();
+
+      combinedInfo.DynamicSegments.push_back(
+          MapInfosTy::DynamicSegment{count, {}, mapType, hasAttachPtr});
+      MapInfosTy::DynamicSegment &seg = combinedInfo.DynamicSegments.back();
+      // Capture `iterInfo` by value: it already holds the lb/ub/step/trip
+      // llvm::Value*s looked up while `declMapperOp`'s region mapping was
+      // still valid. GenEntry runs later (from within
+      // OpenMPIRBuilder::createIteratorLoop), after the mapping for that
+      // region has been dropped below via forgetMapping, so re-deriving a
+      // fresh IteratorInfo from `itersOp` at that point would fail to find
+      // the lb/ub/step values in the (already cleared) ModuleTranslation
+      // value map.
+      seg.GenEntry = [&moduleTranslation, itersOp, mapInfoOp, sizeVal,
+                      iterInfo](llvm::IRBuilderBase &b,
+                                llvm::Value *linearIV) mutable
+          -> llvm::Expected<llvm::SmallVector<llvm::Value *, 3>> {
+        if (failed(convertIteratorRegion(
+                linearIV, iterInfo, itersOp.getRegion(), b, moduleTranslation)))
+          return llvm::make_error<PreviouslyReportedError>();
+        // `mapInfoOp` (the omp.yield operand) has no translated value of its
+        // own; its runtime address is its var_ptr operand.
+        llvm::Value *addr =
+            moduleTranslation.lookupValue(mapInfoOp.getVarPtr());
+        moduleTranslation.forgetMapping(itersOp.getRegion());
+        return llvm::SmallVector<llvm::Value *, 3>{addr, addr, sizeVal};
+      };
+
+      if (mapInfoOp.getMapperId()) {
+        auto childMapperOp =
+            SymbolTable::lookupNearestSymbolFrom<omp::DeclareMapperOp>(
+                mapInfoOp, mapInfoOp.getMapperIdAttr());
+        llvm::Expected<llvm::Function *> childMapperFn =
+            getOrCreateUserDefinedMapperFunc(
----------------
MattPD wrote:

When `getOrCreateUserDefinedMapperFunc` emits the child mapper (`mi` in the reproducer) for the first time, the child's `genMapInfoCB` calls `builder.restoreIP(codeGenIP)`, setting the insertion point of `builder` inside the child function. The insertion point of `builder` remains inside the child function after `getOrCreateUserDefinedMapperFunc` returns.

If another `map_iterated` entry follows, the `IteratorInfo` constructor for that entry passes `builder` to `calculateCanonicalLoopTripCount`. During that call, `updateToLocation` sets the OpenMPIRBuilder's own insertion point inside the child function too. As a result, translation emits the rest of the outer mapper into the child function.

Save the following as `repro.f90`:

```fortran
subroutine f(x)
  type :: inner
    integer :: q
  end type
  type :: t
    integer :: n
    type(inner) :: items(4)
    integer :: b(8)
  end type
  type(t) :: x
  !$omp declare mapper(mi: inner :: w) map(w)
  !$omp declare mapper(m: t :: v) map(mapper(mi), iterator(i=1:2): v%items(i)) map(iterator(j=1:v%n): v%b(j))
  !$omp target data map(mapper(m): x)
  !$omp end target data
end
```

Then run `flang -fc1 -emit-llvm -fopenmp -fopenmp-version=52 -fopenmp-targets=amdgcn-amd-amdhsa repro.f90 -o -`. Flang built with assertions prints `Basic Block in function '.omp_mapper._QQFfm' does not have terminator!` and then fails the assertion `cannot get DomTreeNode of block with different parent`. Before this PR, Flang rejected the same input with `not yet implemented: Support for iterator modifiers is not implemented yet`. If you swap the two `map` clauses, Flang compiles the reproducer.

Could an `llvm::IRBuilderBase::InsertPointGuard` around the `getOrCreateUserDefinedMapperFunc` call restore the insertion point of `builder`? A test with two `map_iterated` entries, the first carrying `mapper(...)`, would exercise child-mapper emission followed by a second iterated entry.

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


More information about the flang-commits mailing list