[flang-commits] [flang] [llvm] [Flang][OpenMP] Fix assert trigger in MapInfoFinalization pass for implicit record member maps (PR #193851)

via flang-commits flang-commits at lists.llvm.org
Tue May 5 09:21:56 PDT 2026


https://github.com/agozillon updated https://github.com/llvm/llvm-project/pull/193851

>From 3f98d62833d9d9efd13c7f2ffa1c470a32d4ece3 Mon Sep 17 00:00:00 2001
From: agozillon <Andrew.Gozillon at amd.com>
Date: Thu, 23 Apr 2026 17:17:22 -0500
Subject: [PATCH] [Flang][OpenMP] Fix assert trigger in MapInfoFinalization
 pass for implicit record member maps

The current iteration of the implicit record member mapping segment of the MapInfoFinalization
pass makes the assumption that child maps of parents are already bound to the targets block
arguments, but that is not the case apon initial lowering from PFT to MLIR. This actually happens
as the end of the MapInfoFinalization pass currently where we "canonicalize" that all maps are
inserted as Block arguments to their respective targets.

This assumption unfortunately leads to a few cases where we trigger the assertion, to address this
we can impose this canonicalization of map <-> block arguments as soon as we enter the pass and then
once again at the end of the pass for any new members generated by the MapInfoFinalization pass. This
allows the implicit record member mapping process to continue unhindered whilst changing very little
elsewhere other than the ordering of block arguments (hence some lit tests tweaks). The main downside
is the extra processing required for running the "canonialization" twice.

I adopted some tests created by @chichunchen in his version of the fix to help test for regressions.

Co-authored-by: @chichunchen
---
 .../Optimizer/OpenMP/MapInfoFinalization.cpp  | 54 +++++++++++++++++--
 ...allocatable-dtype-intermediate-map-gen.f90 |  2 +-
 .../OpenMP/derived-type-allocatable-map.f90   |  4 +-
 ...mp-map-info-finalization-member-record.fir | 42 +++++++++++++++
 .../Transforms/omp-map-info-finalization.fir  |  6 +--
 ...et-map-nested-dtype-allocatable-member.f90 | 33 ++++++++++++
 6 files changed, 132 insertions(+), 9 deletions(-)
 create mode 100644 flang/test/Transforms/omp-map-info-finalization-member-record.fir
 create mode 100644 offload/test/offloading/fortran/target-map-nested-dtype-allocatable-member.f90

diff --git a/flang/lib/Optimizer/OpenMP/MapInfoFinalization.cpp b/flang/lib/Optimizer/OpenMP/MapInfoFinalization.cpp
index bc0f96478ddf4..8cc9ca59f766d 100644
--- a/flang/lib/Optimizer/OpenMP/MapInfoFinalization.cpp
+++ b/flang/lib/Optimizer/OpenMP/MapInfoFinalization.cpp
@@ -958,6 +958,18 @@ class MapInfoFinalizationPass
       localBoxAllocas.clear();
       deferrableDesc.clear();
 
+      // Walk all of the existing maps for parents with child maps and then
+      // make sure to appropriately bind them to the target region that the
+      // parent is bound to. Necessary for the next implicit record member
+      // map step which depends on this canonicalization step. This step
+      // is executed again as the final step of this pass to maintain
+      // map to block argument consistency.
+      func->walk([&](mlir::omp::MapInfoOp op) {
+        mlir::Operation *targetUser = getFirstTargetUser(op);
+        assert(targetUser && "expected user of map operation was not found");
+        addImplicitMembersToTarget(op, builder, targetUser);
+      });
+
       // Next, walk `omp.map.info` ops to see if any record members should be
       // implicitly mapped.
       func->walk([&](mlir::omp::MapInfoOp op) {
@@ -1172,9 +1184,45 @@ class MapInfoFinalizationPass
         // this pass to support multiple users, as we may wish to have a map
         // be re-used by multiple users (e.g. across multiple targets that map
         // the variable and have identical map properties).
-        assert(llvm::hasSingleElement(op->getUsers()) &&
-               "OMPMapInfoFinalization currently only supports single users "
-               "of a MapInfoOp");
+        auto assertCheck = [&](mlir::omp::MapInfoOp op) {
+          if (llvm::hasSingleElement(op->getUsers()))
+            return true;
+
+          if (llvm::range_size(op->getUsers()) > 2)
+            return false;
+
+          // We only allow a TargetOp or MapInfoOp when we have multiple users
+          // for the moment.
+          bool targetUser = false;
+          for (auto *user : op->getUsers()) {
+            if (targetUser && !llvm::isa<
+                    mlir::omp::TargetOp, mlir::omp::TargetDataOp,
+                    mlir::omp::TargetUpdateOp, mlir::omp::TargetExitDataOp,
+                    mlir::omp::TargetEnterDataOp,
+                    mlir::omp::DeclareMapperInfoOp, mlir::omp::MapInfoOp>(user))
+              return false;
+
+            // We do not handle multiple target users currently.
+            if (targetUser &&
+                llvm::isa<mlir::omp::TargetDataOp, mlir::omp::TargetUpdateOp,
+                          mlir::omp::TargetExitDataOp,
+                          mlir::omp::TargetEnterDataOp>(user))
+              return false;
+
+            if (!targetUser)
+              targetUser =
+                  llvm::isa<mlir::omp::TargetDataOp, mlir::omp::TargetUpdateOp,
+                            mlir::omp::TargetExitDataOp,
+                            mlir::omp::TargetEnterDataOp>(user);
+          }
+
+          return true;
+        };
+
+        assert(assertCheck(op) &&
+               "OMPMapInfoFinalization currently only supports "
+               "single users or up to two users when those users"
+               "are a MapInfoOp and Target mapping directive");
 
         if (hasADescriptor(op.getVarPtr().getDefiningOp(),
                            fir::unwrapRefType(op.getVarType()))) {
diff --git a/flang/test/Lower/OpenMP/allocatable-dtype-intermediate-map-gen.f90 b/flang/test/Lower/OpenMP/allocatable-dtype-intermediate-map-gen.f90
index 0da277b7afd96..bc83cfe97769b 100644
--- a/flang/test/Lower/OpenMP/allocatable-dtype-intermediate-map-gen.f90
+++ b/flang/test/Lower/OpenMP/allocatable-dtype-intermediate-map-gen.f90
@@ -14,7 +14,7 @@ subroutine target_map_to()
 
 !CHECK: %[[DTYPE_DATA:.*]] = omp.map.info var_ptr(%{{.*}} : !fir.ref<!fir.box<!fir.heap<!fir.type<_QFtarget_map_toTdtype{scalar:!fir.box<!fir.heap<i32>>}>>>>, !fir.type<_QFtarget_map_toTdtype{scalar:!fir.box<!fir.heap<i32>>}>) map_clauses(to) capture(ByRef) var_ptr_ptr({{.*}} : !fir.llvm_ptr<!fir.ref<!fir.type<_QFtarget_map_toTdtype{scalar:!fir.box<!fir.heap<i32>>}>>>) -> !fir.llvm_ptr<!fir.ref<!fir.type<_QFtarget_map_toTdtype{scalar:!fir.box<!fir.heap<i32>>}>>> {name = ""}
 !CHECK: %[[DTYPE_DESC:.*]] = omp.map.info var_ptr(%{{.*}} : !fir.ref<!fir.box<!fir.heap<!fir.type<_QFtarget_map_toTdtype{scalar:!fir.box<!fir.heap<i32>>}>>>>, !fir.box<!fir.heap<!fir.type<_QFtarget_map_toTdtype{scalar:!fir.box<!fir.heap<i32>>}>>>) map_clauses(always, to) capture(ByRef) members({{.*}} : !fir.llvm_ptr<!fir.ref<!fir.type<_QFtarget_map_toTdtype{scalar:!fir.box<!fir.heap<i32>>}>>>, !fir.ref<!fir.box<!fir.heap<i32>>>, !fir.llvm_ptr<!fir.ref<i32>>) -> !fir.ref<!fir.box<!fir.heap<!fir.type<_QFtarget_map_toTdtype{scalar:!fir.box<!fir.heap<i32>>}>>>> {name = "derived"}
-!CHECK: omp.target map_entries(%[[DTYPE_DESC]] -> %{{.*}}, %[[DTYPE_DATA]] -> %{{.*}}, %[[SCALAR_DESC]] -> %{{.*}}, %[[SCALAR_DATA]] -> %{{.*}} : !fir.ref<!fir.box<!fir.heap<!fir.type<_QFtarget_map_toTdtype{scalar:!fir.box<!fir.heap<i32>>}>>>>, !fir.llvm_ptr<!fir.ref<!fir.type<_QFtarget_map_toTdtype{scalar:!fir.box<!fir.heap<i32>>}>>>, !fir.ref<!fir.box<!fir.heap<i32>>>, !fir.llvm_ptr<!fir.ref<i32>>) {
+!CHECK: omp.target map_entries(%[[DTYPE_DESC]] -> %{{.*}}, %[[SCALAR_DESC]] -> %{{.*}}, %[[DTYPE_DATA]] -> %{{.*}}, %[[SCALAR_DATA]] -> %{{.*}} : !fir.ref<!fir.box<!fir.heap<!fir.type<_QFtarget_map_toTdtype{scalar:!fir.box<!fir.heap<i32>>}>>>>, !fir.ref<!fir.box<!fir.heap<i32>>>, !fir.llvm_ptr<!fir.ref<!fir.type<_QFtarget_map_toTdtype{scalar:!fir.box<!fir.heap<i32>>}>>>, !fir.llvm_ptr<!fir.ref<i32>>) {
 
 !$omp target map(to:derived%scalar)
 !$omp end target
diff --git a/flang/test/Lower/OpenMP/derived-type-allocatable-map.f90 b/flang/test/Lower/OpenMP/derived-type-allocatable-map.f90
index 74aee4df1f454..f5ed6c82277b7 100644
--- a/flang/test/Lower/OpenMP/derived-type-allocatable-map.f90
+++ b/flang/test/Lower/OpenMP/derived-type-allocatable-map.f90
@@ -43,7 +43,7 @@ subroutine dtype_alloca_map_op_block()
 !CHECK: %[[DTYPE_BASE_ADDR:.*]] = fir.box_offset %[[DECLARE]]#1 base_addr : (!fir.ref<!fir.box<!fir.heap<!fir.type<[[REC_TY]]>>>>) -> !fir.llvm_ptr<!fir.ref<!fir.type<[[REC_TY]]>>>
 !CHECK: %[[MAP_DTYPE_BASE_ADDR:.*]] = omp.map.info var_ptr(%[[DECLARE]]#1 : !fir.ref<!fir.box<!fir.heap<!fir.type<[[REC_TY]]>>>>, !fir.type<[[REC_TY]]>)  map_clauses(tofrom) capture(ByRef) var_ptr_ptr(%[[DTYPE_BASE_ADDR]] : !fir.llvm_ptr<!fir.ref<!fir.type<[[REC_TY]]>>>) -> !fir.llvm_ptr<!fir.ref<!fir.type<[[REC_TY]]>>> {{.*}}
 !CHECK: %[[MAP_DTYPE_DESC:.*]] = omp.map.info var_ptr(%[[DECLARE]]#1 : !fir.ref<!fir.box<!fir.heap<!fir.type<[[REC_TY]]>>>>, !fir.box<!fir.heap<!fir.type<[[REC_TY]]>>>) map_clauses(always, to) capture(ByRef) members(%[[MAP_DTYPE_BASE_ADDR]], %[[MAP_MEMBER_DESC]], %[[MAP_MEMBER_BASE_ADDR]], %[[MAP_REGULAR_MEMBER]] : [0], [0, 4], [0, 4, 0], [0, 5] : !fir.llvm_ptr<!fir.ref<!fir.type<[[REC_TY]]>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>, !fir.ref<i32>) -> !fir.ref<!fir.box<!fir.heap<!fir.type<[[REC_TY]]>>>> {{.*}}
-!CHECK: omp.target map_entries(%[[MAP_DTYPE_DESC]] -> %[[ARG0:.*]], %[[MAP_DTYPE_BASE_ADDR]] -> %[[ARG1:.*]], %[[MAP_MEMBER_DESC]] -> %[[ARG2:.*]], %[[MAP_MEMBER_BASE_ADDR]] -> %[[ARG3:.*]], %[[MAP_REGULAR_MEMBER]] -> %[[ARG4:.*]] : !fir.ref<!fir.box<!fir.heap<!fir.type<[[REC_TY]]>>>>, !fir.llvm_ptr<!fir.ref<!fir.type<[[REC_TY]]>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>, !fir.ref<i32>) {
+!CHECK: omp.target map_entries(%[[MAP_DTYPE_DESC]] -> %[[ARG0:.*]], %[[MAP_MEMBER_DESC]] -> %[[ARG1:.*]], %[[MAP_REGULAR_MEMBER]] -> %[[ARG2:.*]], %[[MAP_DTYPE_BASE_ADDR]] -> %[[ARG3:.*]], %[[MAP_MEMBER_BASE_ADDR]] -> %[[ARG4:.*]] : !fir.ref<!fir.box<!fir.heap<!fir.type<[[REC_TY]]>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<i32>, !fir.llvm_ptr<!fir.ref<!fir.type<[[REC_TY]]>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) {
 !CHECK:  %{{.*}}:2 = hlfir.declare %[[ARG0]] {{{.*}}} : (!fir.ref<!fir.box<!fir.heap<!fir.type<[[REC_TY]]>>>>) -> (!fir.ref<!fir.box<!fir.heap<!fir.type<[[REC_TY]]>>>>, !fir.ref<!fir.box<!fir.heap<!fir.type<[[REC_TY]]>>>>)
 subroutine alloca_dtype_op_block_add()
     type :: one_layer
@@ -82,7 +82,7 @@ subroutine alloca_dtype_op_block_add()
 !CHECK: %[[DTYPE_BASE_ADDR:.*]] = fir.box_offset %[[DECLARE]]#1 base_addr : (!fir.ref<!fir.box<!fir.heap<!fir.type<[[REC_TY]]>}>>>>) -> !fir.llvm_ptr<!fir.ref<!fir.type<[[REC_TY]]>}>>>
 !CHECK: %[[MAP_DTYPE_BASE_ADDR:.*]] = omp.map.info var_ptr(%[[DECLARE]]#1 : !fir.ref<!fir.box<!fir.heap<!fir.type<[[REC_TY]]>}>>>>, !fir.type<[[REC_TY]]>}>) map_clauses(tofrom) capture(ByRef) var_ptr_ptr(%[[DTYPE_BASE_ADDR]] : !fir.llvm_ptr<!fir.ref<!fir.type<[[REC_TY]]>}>>>) -> !fir.llvm_ptr<!fir.ref<!fir.type<[[REC_TY]]>}>>> {{.*}}
 !CHECK: %[[MAP_DTYPE:.*]] = omp.map.info var_ptr(%[[DECLARE]]#1 : !fir.ref<!fir.box<!fir.heap<!fir.type<[[REC_TY]]>}>>>>, !fir.box<!fir.heap<!fir.type<[[REC_TY]]>}>>>) map_clauses(always, to) capture(ByRef) members(%[[MAP_DTYPE_BASE_ADDR]], %[[MAP_NESTED_MEMBER_COORD]], %[[MAP_NESTED_MEMBER_BASE_ADDR]], %[[MAP_REGULAR_NESTED_MEMBER]] : [0], [0, 6, 2], [0, 6, 2, 0], [0, 6, 3] : !fir.llvm_ptr<!fir.ref<!fir.type<[[REC_TY]]>}>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>, !fir.ref<i32>) -> !fir.ref<!fir.box<!fir.heap<!fir.type<[[REC_TY]]>}>>>> {{.*}}
-!CHECK: omp.target map_entries(%[[MAP_DTYPE]] -> %[[ARG0:.*]], %[[MAP_DTYPE_BASE_ADDR]] -> %[[ARG1:.*]], %[[MAP_NESTED_MEMBER_COORD]] -> %[[ARG2:.*]], %[[MAP_NESTED_MEMBER_BASE_ADDR]] -> %[[ARG3:.*]], %[[MAP_REGULAR_NESTED_MEMBER]] -> %[[ARG4:.*]] : !fir.ref<!fir.box<!fir.heap<!fir.type<[[REC_TY]]>}>>>>, !fir.llvm_ptr<!fir.ref<!fir.type<[[REC_TY]]>}>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>, !fir.ref<i32>) {
+!CHECK: omp.target map_entries(%[[MAP_DTYPE]] -> %[[ARG0:.*]], %[[MAP_NESTED_MEMBER_COORD]] -> %[[ARG1:.*]], %[[MAP_REGULAR_NESTED_MEMBER]] -> %[[ARG2:.*]], %[[MAP_DTYPE_BASE_ADDR]] -> %[[ARG3:.*]], %[[MAP_NESTED_MEMBER_BASE_ADDR]] -> %[[ARG4:.*]] : !fir.ref<!fir.box<!fir.heap<!fir.type<[[REC_TY]]>}>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<i32>, !fir.llvm_ptr<!fir.ref<!fir.type<[[REC_TY]]>}>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) {
 !CHECK:  %{{.*}}:2 = hlfir.declare %[[ARG0]] {{.*}} : (!fir.ref<!fir.box<!fir.heap<!fir.type<[[REC_TY]]>}>>>>) -> (!fir.ref<!fir.box<!fir.heap<!fir.type<[[REC_TY]]>}>>>>, !fir.ref<!fir.box<!fir.heap<!fir.type<[[REC_TY]]>}>>>>)
 subroutine alloca_nest_dype_map_op_block_add()
     type :: middle_layer
diff --git a/flang/test/Transforms/omp-map-info-finalization-member-record.fir b/flang/test/Transforms/omp-map-info-finalization-member-record.fir
new file mode 100644
index 0000000000000..6714790d92d58
--- /dev/null
+++ b/flang/test/Transforms/omp-map-info-finalization-member-record.fir
@@ -0,0 +1,42 @@
+// RUN: fir-opt --omp-map-info-finalization %s | FileCheck %s
+// This tests that we are appropriately handling derived type mappings in the
+// MapInfoFinalization pass, making sure that we connect the members contained
+// by the parent to the target region using the parent, before processing
+// further.
+//
+// The initial lowering just inserts the members into the parent, it's up to the
+// MapInfoFinalization pass to connect these members (and any expanded members)
+// to the targets block arguments, this is primarily done for canonicalization of
+// the target region input arguments. However, some steps in the MapInfoFinalization
+// pass depend on this canon representation (primarily the implicit mapping), so we
+// must make sure this step occurs a the beginning and end of the pass to prevent
+// issues.
+
+!t1 = !fir.type<_QFTt1{a:!fir.box<!fir.heap<i32>>}>
+!t2 = !fir.type<_QFTt2{b:!fir.type<_QFTt1{a:!fir.box<!fir.heap<i32>>}>}>
+
+func.func @test_member_map_not_direct_target_operand(%arg0: !fir.ref<!t2>, %arg1: !fir.ref<!t2>) {
+  %0:2 = hlfir.declare %arg0 {uniq_name = "_QFEvar1"} : (!fir.ref<!t2>) -> (!fir.ref<!t2>, !fir.ref<!t2>)
+  %1:2 = hlfir.declare %arg1 {uniq_name = "_QFEvar2"} : (!fir.ref<!t2>) -> (!fir.ref<!t2>, !fir.ref<!t2>)
+
+  %b1 = hlfir.designate %0#0{"b"} : (!fir.ref<!t2>) -> !fir.ref<!t1>
+  %b2 = hlfir.designate %1#0{"b"} : (!fir.ref<!t2>) -> !fir.ref<!t1>
+
+  %map_b1 = omp.map.info var_ptr(%b1 : !fir.ref<!t1>, !t1) map_clauses(to) capture(ByRef) -> !fir.ref<!t1> {name = "var1%b"}
+  %map_b2 = omp.map.info var_ptr(%b2 : !fir.ref<!t1>, !t1) map_clauses(tofrom) capture(ByRef) -> !fir.ref<!t1> {name = "var2%b"}
+
+  %map_var1 = omp.map.info var_ptr(%0#1 : !fir.ref<!t2>, !t2) map_clauses(to) capture(ByRef) members(%map_b1 : [0] : !fir.ref<!t1>) -> !fir.ref<!t2> {name = "var1", partial_map = true}
+  %map_var2 = omp.map.info var_ptr(%1#1 : !fir.ref<!t2>, !t2) map_clauses(tofrom) capture(ByRef) members(%map_b2 : [0] : !fir.ref<!t1>) -> !fir.ref<!t2> {name = "var2", partial_map = true}
+
+  omp.target map_entries(%map_var1 -> %a0, %map_var2 -> %a1 : !fir.ref<!t2>, !fir.ref<!t2>) {
+    omp.terminator
+  }
+  return
+}
+
+// CHECK-LABEL: func.func @test_member_map_not_direct_target_operand
+// CHECK: %[[MAP_B1:.*]] = omp.map.info {{.*}} map_clauses(to) {{.*}} {name = "var1%b"}
+// CHECK: %[[MAP_B2:.*]] = omp.map.info {{.*}} map_clauses(tofrom) {{.*}} {name = "var2%b"}
+// CHECK: %[[MAP_VAR1:.*]] = omp.map.info {{.*}} members(%[[MAP_B1]] : [0] : {{.*}}) {{.*}} {name = "var1", partial_map = true}
+// CHECK: %[[MAP_VAR2:.*]] = omp.map.info {{.*}} members(%[[MAP_B2]] : [0] : {{.*}}) {{.*}} {name = "var2", partial_map = true}
+// CHECK: omp.target map_entries(%[[MAP_VAR1]] -> %{{.*}}, %[[MAP_VAR2]] -> %{{.*}}, %[[MAP_B1]] -> %{{.*}}, %[[MAP_B2]] -> %{{.*}} :
\ No newline at end of file
diff --git a/flang/test/Transforms/omp-map-info-finalization.fir b/flang/test/Transforms/omp-map-info-finalization.fir
index a808b81e71356..3fb683aec7327 100644
--- a/flang/test/Transforms/omp-map-info-finalization.fir
+++ b/flang/test/Transforms/omp-map-info-finalization.fir
@@ -159,7 +159,7 @@ func.func @alloca_dtype_map_op_block_add(%arg0 : !fir.ref<!fir.box<!fir.heap<!fi
 // CHECK:     %[[ALLOCATABLE_PARENT_BASE_ADDR:.*]] = fir.box_offset %[[ALLOCA]]#1 base_addr : (!fir.ref<!fir.box<!fir.heap<!fir.type<[[REC_TY]]>>>>) -> !fir.llvm_ptr<!fir.ref<!fir.type<[[REC_TY]]>>>
 // CHECK:     %[[MAP_ALLOCA_PARENT_BASE_ADDR:.*]] = omp.map.info var_ptr(%[[ALLOCA]]#1 : !fir.ref<!fir.box<!fir.heap<!fir.type<[[REC_TY]]>>>>, !fir.type<[[REC_TY]]>) map_clauses(tofrom) capture(ByRef) var_ptr_ptr(%[[ALLOCATABLE_PARENT_BASE_ADDR]] : !fir.llvm_ptr<!fir.ref<!fir.type<[[REC_TY]]>>>) -> !fir.llvm_ptr<!fir.ref<!fir.type<[[REC_TY]]>>> {{.*}}
 // CHECK:     %[[MAP_PARENT_DESCRIPTOR:.*]] = omp.map.info var_ptr(%[[ALLOCA]]#1 : !fir.ref<!fir.box<!fir.heap<!fir.type<[[REC_TY]]>>>>, !fir.box<!fir.heap<!fir.type<[[REC_TY]]>>>) map_clauses(always, to) capture(ByRef) members(%18, %13, %12, %16 : [0], [0, 4], [0, 4, 0], [0, 5] : !fir.llvm_ptr<!fir.ref<!fir.type<[[REC_TY]]>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>, !fir.ref<i32>) -> !fir.ref<!fir.box<!fir.heap<!fir.type<[[REC_TY]]>>>> {{.*}}
-// CHECK:    omp.target map_entries(%[[MAP_PARENT_DESCRIPTOR]] -> %[[ARG1:.*]], %[[MAP_ALLOCA_PARENT_BASE_ADDR]] -> %[[ARG2:.*]], %[[MAP_ALLOCA_MEMBER_DESCRIPTOR]] -> %[[ARG3:.*]], %[[MAP_ALLOCA_MEMBER_BASE_ADDR]] -> %[[ARG4:.*]], %[[MAP_REGULAR_MEMBER]] -> %[[ARG5:.*]] : !fir.ref<!fir.box<!fir.heap<!fir.type<[[REC_TY]]>>>>, !fir.llvm_ptr<!fir.ref<!fir.type<[[REC_TY]]>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>, !fir.ref<i32>) {
+// CHECK:    omp.target map_entries(%[[MAP_PARENT_DESCRIPTOR]] -> %[[ARG1:.*]], %[[MAP_ALLOCA_MEMBER_DESCRIPTOR]] -> %[[ARG2:.*]], %[[MAP_REGULAR_MEMBER]] -> %[[ARG3:.*]], %[[MAP_ALLOCA_PARENT_BASE_ADDR]] -> %[[ARG4:.*]], %[[MAP_ALLOCA_MEMBER_BASE_ADDR]] -> %[[ARG5:.*]] : !fir.ref<!fir.box<!fir.heap<!fir.type<[[REC_TY]]>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<i32>, !fir.llvm_ptr<!fir.ref<!fir.type<[[REC_TY]]>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) {
 
 // -----
 
@@ -210,7 +210,7 @@ func.func @alloca_dtype_map_op_block_add(%arg0 : !fir.ref<!fir.box<!fir.heap<!fi
 // CHECK:   %[[ALLOCATABLE_PARENT_BASE_ADDR:.*]] = fir.box_offset %[[ALLOCA]]#1 base_addr : (!fir.ref<!fir.box<!fir.heap<!fir.type<[[REC_TY]]>>>>) -> !fir.llvm_ptr<!fir.ref<!fir.type<[[REC_TY]]>>>
 // CHECK:   %[[MAP_ALLOCATABLE_PARENT_BASE_ADDR:.*]] = omp.map.info var_ptr(%[[ALLOCA]]#1 : !fir.ref<!fir.box<!fir.heap<!fir.type<[[REC_TY]]>>>>, !fir.type<[[REC_TY]]>) map_clauses(tofrom) capture(ByRef) var_ptr_ptr(%[[ALLOCATABLE_PARENT_BASE_ADDR]] : !fir.llvm_ptr<!fir.ref<!fir.type<[[REC_TY]]>>>) -> !fir.llvm_ptr<!fir.ref<!fir.type<[[REC_TY]]>>> {{.*}}
 // CHECK:   %[[MAP_ALLOCATABLE_PARENT_DESCRIPTOR:.*]] = omp.map.info var_ptr(%[[ALLOCA]]#1 : !fir.ref<!fir.box<!fir.heap<!fir.type<[[REC_TY]]>>>>, !fir.box<!fir.heap<!fir.type<[[REC_TY]]>>>) map_clauses(always, to) capture(ByRef) members(%21, %15, %14, %19 : [0], [0, 6, 2], [0, 6, 2, 0], [0, 6, 3] : !fir.llvm_ptr<!fir.ref<!fir.type<[[REC_TY]]>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>, !fir.ref<i32>) -> !fir.ref<!fir.box<!fir.heap<!fir.type<[[REC_TY]]>>>> {{.*}}
-// CHECK:    omp.target map_entries(%[[MAP_ALLOCATABLE_PARENT_DESCRIPTOR]] -> %[[ARG1:.*]], %[[MAP_ALLOCATABLE_PARENT_BASE_ADDR]] -> %[[ARG2:.*]], %[[MAP_NESTED_ALLOCA_MEMBER]] -> %[[ARG3:.*]], %[[MAP_NESTED_ALLOCA_MEMBER_BASE_ADDR]] -> %[[ARG4:.*]], %[[MAP_NESTED_REGULAR_MEMBER]] -> %[[ARG5:.*]] : !fir.ref<!fir.box<!fir.heap<!fir.type<[[REC_TY]]>>>>, !fir.llvm_ptr<!fir.ref<!fir.type<[[REC_TY]]>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>, !fir.ref<i32>) {
+// CHECK:    omp.target map_entries(%[[MAP_ALLOCATABLE_PARENT_DESCRIPTOR]] -> %[[ARG1:.*]], %[[MAP_NESTED_ALLOCA_MEMBER]] -> %[[ARG2:.*]], %[[MAP_NESTED_REGULAR_MEMBER]] -> %[[ARG3:.*]], %[[MAP_ALLOCATABLE_PARENT_BASE_ADDR]] -> %[[ARG4:.*]], %[[MAP_NESTED_ALLOCA_MEMBER_BASE_ADDR]] -> %[[ARG5:.*]] : !fir.ref<!fir.box<!fir.heap<!fir.type<[[REC_TY]]>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<i32>, !fir.llvm_ptr<!fir.ref<!fir.type<[[REC_TY]]>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) {
 
 // -----
 
@@ -286,7 +286,7 @@ func.func @alloca_dtype_map_op_block_add(%arg0 : !fir.ref<!fir.box<!fir.heap<!fi
 // CHECK:    %[[BASE_ADDR_MAP_2:.*]] = omp.map.info var_ptr(%[[DESC_2]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, i32) map_clauses(tofrom) capture(ByRef) var_ptr_ptr(%[[BASE_ADDR_2]] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) bounds(%{{.*}}) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>> {{.*}}
 // CHECK:    %[[DESC_MAP_2:.*]] = omp.map.info var_ptr(%[[DESC_2]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.box<!fir.heap<!fir.array<?xi32>>>) map_clauses(always, to) capture(ByRef) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>> {{.*}}
 // CHECK:    %[[TOP_PARENT_MAP:.*]] = omp.map.info var_ptr(%0#1 : !fir.ref<!fir.type<[[REC_TY]]>>, !fir.type<[[REC_TY]]>) map_clauses(storage) capture(ByRef) members(%6, %5, %14, %13 : [1], [1, 0], [1, 0, 2], [1, 0, 2, 0] : !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.type<[[REC_TY2]]>>>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?x!fir.type<[[REC_TY2]]>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) -> !fir.ref<!fir.type<[[REC_TY]]>> {{{.*}} partial_map = true}
-// CHECK:    omp.target map_entries(%[[TOP_PARENT_MAP]] -> %{{.*}}, %[[DESC_MAP_1]] -> %{{.*}}, %[[BASE_ADDR_MAP_1]] -> %{{.*}}, %[[DESC_MAP_2]] -> %{{.*}}, %[[BASE_ADDR_MAP_2]] -> %{{.*}} : !fir.ref<!fir.type<[[REC_TY]]>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.type<[[REC_TY2]]>>>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?x!fir.type<[[REC_TY2]]>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) {
+// CHECK:    omp.target map_entries(%[[TOP_PARENT_MAP]] -> %{{.*}}, %[[DESC_MAP_1]] -> %{{.*}}, %[[DESC_MAP_2]] -> %{{.*}}, %[[BASE_ADDR_MAP_1]] -> %{{.*}}, %[[BASE_ADDR_MAP_2]] -> %{{.*}} : !fir.ref<!fir.type<[[REC_TY]]>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.type<[[REC_TY2]]>>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?x!fir.type<[[REC_TY2]]>>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) {
 
 // -----
 
diff --git a/offload/test/offloading/fortran/target-map-nested-dtype-allocatable-member.f90 b/offload/test/offloading/fortran/target-map-nested-dtype-allocatable-member.f90
new file mode 100644
index 0000000000000..4d6edae33e4da
--- /dev/null
+++ b/offload/test/offloading/fortran/target-map-nested-dtype-allocatable-member.f90
@@ -0,0 +1,33 @@
+! Offloading test checking that mapping two variables of a derived type
+! containing a nested derived type with an allocatable member does not crash
+! during MapInfoFinalization. The member maps for the inner derived type are
+! not direct target operands; the pass must skip them when walking record types
+! with allocatable members.
+! REQUIRES: flang, amdgpu
+
+! RUN: %libomptarget-compile-fortran-run-and-check-generic
+program main
+    type :: inner_type
+      integer, allocatable :: a
+    end type inner_type
+
+    type :: outer_type
+      type(inner_type) :: b
+    end type outer_type
+
+    type(outer_type) :: var1, var2
+
+    allocate(var1%b%a)
+    allocate(var2%b%a)
+    var1%b%a = 10
+    var2%b%a = 20
+
+    !$omp target map(tofrom: var1%b, var2%b)
+      var1%b%a = var1%b%a + var2%b%a
+    !$omp end target
+
+    print *, var1%b%a
+
+end program main
+
+!CHECK: 30



More information about the flang-commits mailing list