[flang-commits] [flang] f55080d - [flang][OpenMP] Avoid implicit default mapper on pointer captures (#184382)

via flang-commits flang-commits at lists.llvm.org
Wed Mar 4 07:27:12 PST 2026


Author: Akash Banerjee
Date: 2026-03-04T15:27:06Z
New Revision: f55080da988a68da6736407b34eafd00817b7143

URL: https://github.com/llvm/llvm-project/commit/f55080da988a68da6736407b34eafd00817b7143
DIFF: https://github.com/llvm/llvm-project/commit/f55080da988a68da6736407b34eafd00817b7143.diff

LOG: [flang][OpenMP] Avoid implicit default mapper on pointer captures (#184382)

This change fixes incorrect implicit declare mapper behavior in Flang
OpenMP lowering.

Issue:
Implicit default mappers were being attached/generated for pointer-based
implicit captures, and also on data-motion directives. That could
trigger recursive component mapping that overlaps/conflicts with
explicit user mappings, causing runtime mapping failures.

Fix:

- Skip implicit default mapper generation for implicit pointer captures
(keep support for allocatables).
- Do not auto-attach implicit mappers on target enter data, target exit
data, or target update.
- Apply the same pointer guard in the implicit target-capture lowering
path.

Added: 
    flang/test/Lower/OpenMP/implicit-map-pointer-no-default-mapper.f90

Modified: 
    flang/lib/Lower/OpenMP/ClauseProcessor.cpp
    flang/lib/Lower/OpenMP/OpenMP.cpp
    flang/test/Lower/OpenMP/target-data-skip-mapper-calls.f90

Removed: 
    


################################################################################
diff  --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
index 85493bf45453e..e437ba103a258 100644
--- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
+++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
@@ -1485,9 +1485,21 @@ void ClauseProcessor::processMapObjects(
         mapperId = mlir::FlatSymbolRefAttr();
       } else if (objectTypeSpec) {
         std::string mapperIdName = getDefaultMapperID(objectTypeSpec);
+        bool isAllocOrPointer =
+            semantics::IsAllocatableOrObjectPointer(object.sym());
+        bool isPointer = semantics::IsPointer(*object.sym());
+        bool isImplicitMap =
+            (mapTypeBits & mlir::omp::ClauseMapFlags::implicit) ==
+            mlir::omp::ClauseMapFlags::implicit;
         bool needsDefaultMapper =
-            semantics::IsAllocatableOrObjectPointer(object.sym()) ||
+            isAllocOrPointer ||
             requiresImplicitDefaultDeclareMapper(*objectTypeSpec);
+        // For implicit captures, avoid synthesizing default mappers for pointer
+        // entities (which can over-map pointer payloads) and for plain
+        // non-allocatable/non-pointer entities. Keep implicit mapper support
+        // for allocatables.
+        if (isImplicitMap && (isPointer || !isAllocOrPointer))
+          needsDefaultMapper = false;
         if (!mapperIdName.empty())
           mapperId = addImplicitMapper(object, mapperIdName,
                                        /*allowGenerate=*/needsDefaultMapper);
@@ -1568,7 +1580,14 @@ bool ClauseProcessor::processMap(
     if (attachMod)
       TODO(currentLocation, "ATTACH modifier is not implemented yet");
     mlir::omp::ClauseMapFlags mapTypeBits = mlir::omp::ClauseMapFlags::none;
+    // For data-motion directives we avoid auto-attaching implicit default
+    // mappers. Deep recursive mapping there can conflict with explicit
+    // component enter/exit maps users commonly spell out.
     std::string mapperIdName = "__implicit_mapper";
+    if (directive == llvm::omp::Directive::OMPD_target_enter_data ||
+        directive == llvm::omp::Directive::OMPD_target_exit_data ||
+        directive == llvm::omp::Directive::OMPD_target_update)
+      mapperIdName.clear();
     // If the map type is specified, then process it else set the appropriate
     // default value
     Map::MapType type;

diff  --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index 0676b1ce0ce53..89af32121487b 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -2848,11 +2848,14 @@ genTargetOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
                 converter.mangleName(mapperIdName, *typeSpec->GetScope());
 
           if (!mapperIdName.empty()) {
-            bool allowImplicitMapper =
-                semantics::IsAllocatableOrObjectPointer(&sym);
+            bool isPointer = semantics::IsPointer(sym);
+            bool isAllocatable = semantics::IsAllocatable(sym);
             bool hasDefaultMapper =
                 converter.getModuleOp().lookupSymbol(mapperIdName);
-            if (hasDefaultMapper || allowImplicitMapper) {
+            // Avoid attaching implicit default mappers to pointer captures.
+            // For large pointer-based derived aggregates this can over-map
+            // nested payloads and conflict with explicit enter/exit maps.
+            if (!isPointer && (hasDefaultMapper || isAllocatable)) {
               if (!hasDefaultMapper) {
                 if (auto recordType = mlir::dyn_cast_or_null<fir::RecordType>(
                         converter.genType(*typeSpec)))

diff  --git a/flang/test/Lower/OpenMP/implicit-map-pointer-no-default-mapper.f90 b/flang/test/Lower/OpenMP/implicit-map-pointer-no-default-mapper.f90
new file mode 100644
index 0000000000000..60a6db69acfa8
--- /dev/null
+++ b/flang/test/Lower/OpenMP/implicit-map-pointer-no-default-mapper.f90
@@ -0,0 +1,26 @@
+! RUN: %flang_fc1 -emit-hlfir -fopenmp %s -o - | FileCheck %s
+program p
+  type t
+    integer :: x
+  end type
+
+  type(t), pointer :: ptr
+  type(t), allocatable :: al
+  allocate(ptr, al)
+
+  !$omp target
+    ptr%x = ptr%x + 1
+    al%x = al%x + 1
+  !$omp end target
+end program
+
+! CHECK-LABEL: omp.declare_mapper @_QQFt_omp_default_mapper
+
+! CHECK-LABEL: func.func @_QQmain
+! The pointer capture should not get an implicit default mapper.
+! CHECK: %[[PTR_PTEE_MAP:.*]] = omp.map.info {{.*}}map_clauses(implicit, tofrom){{.*}} {name = ""}
+! CHECK: %[[PTR_DESC_MAP:.*]] = omp.map.info {{.*}}members(%[[PTR_PTEE_MAP]]{{.*}}){{.*}} {name = "ptr"}
+
+! The allocatable capture should still use the implicit default mapper.
+! CHECK: %[[ALLOC_PTEE_MAP:.*]] = omp.map.info {{.*}}map_clauses(implicit, tofrom){{.*}}mapper(@_QQFt_omp_default_mapper){{.*}} {name = ""}
+! CHECK: %[[ALLOC_DESC_MAP:.*]] = omp.map.info {{.*}}members(%[[ALLOC_PTEE_MAP]]{{.*}}){{.*}} {name = "al"}

diff  --git a/flang/test/Lower/OpenMP/target-data-skip-mapper-calls.f90 b/flang/test/Lower/OpenMP/target-data-skip-mapper-calls.f90
index d1d441d0a7c0c..e2302873bd68e 100644
--- a/flang/test/Lower/OpenMP/target-data-skip-mapper-calls.f90
+++ b/flang/test/Lower/OpenMP/target-data-skip-mapper-calls.f90
@@ -23,8 +23,14 @@ program test
 
 subroutine f(x, y)
   integer :: x, y
+  type :: t
+    integer, pointer :: p(:)
+  end type
+  type(t) :: d
   !$omp target data map(tofrom: x, y)
   x = x + y
   !$omp end target data
+  !$omp target enter data map(to: d)
+  !$omp target exit data map(release: d)
 end subroutine
 end


        


More information about the flang-commits mailing list