[flang-commits] [flang] [llvm] [Flang][OpenMP] Turn off NYI for nested record type maps in DoConcurrentConversion.cpp (PR #220099)
via flang-commits
flang-commits at lists.llvm.org
Mon Aug 31 14:46:23 PDT 2026
https://github.com/agozillon created https://github.com/llvm/llvm-project/pull/220099
This should be supported in two ways, regular non-allocatable carrying derived types need no special handling, a map of the record type captures the entirety of the record type. For allocatables inside of them the mapper should handle this scenario.
>From d4bff66fd2d1dd5dd8dfc4bbb83657c0ed7a1831 Mon Sep 17 00:00:00 2001
From: agozillon <Andrew.Gozillon at amd.com>
Date: Mon, 31 Aug 2026 14:04:38 -0500
Subject: [PATCH] [Flang][OpenMP] Turn off NYI for nested record type maps in
DoConcurrentConversion.cpp
This should be supported in two ways, regular non-allocatable carrying derived types
need no special handling, a map of the record type captures the entirety of the record
type. For allocatables inside of them the mapper should handle this scenario.
---
.../OpenMP/DoConcurrentConversion.cpp | 18 +---
...concurrent_nested_derived_type_mapping.f90 | 87 +++++++++++++++++++
...-concurrent-to-omp-nested-derived-type.f90 | 50 +++++++++++
3 files changed, 138 insertions(+), 17 deletions(-)
create mode 100644 flang/test/Lower/OpenMP/do_concurrent_nested_derived_type_mapping.f90
create mode 100644 offload/test/offloading/fortran/do-concurrent-to-omp-nested-derived-type.f90
diff --git a/flang/lib/Optimizer/OpenMP/DoConcurrentConversion.cpp b/flang/lib/Optimizer/OpenMP/DoConcurrentConversion.cpp
index 4dc6aa4750eaa..f2f9fc46810f5 100644
--- a/flang/lib/Optimizer/OpenMP/DoConcurrentConversion.cpp
+++ b/flang/lib/Optimizer/OpenMP/DoConcurrentConversion.cpp
@@ -602,24 +602,8 @@ class DoConcurrentConversion
};
fir::RecordType recordType = asRecordType(eleType);
-
- bool requiresImplcitMapper = [&]() {
- if (!recordType)
- return false;
-
- for (auto [fieldName, fieldType] : recordType.getTypeList()) {
- if (fir::isAllocatableType(fieldType))
- return true;
-
- if (asRecordType(fieldType))
- TODO(liveIn.getLoc(), "Nested record types are not supported yet.");
- }
-
- return false;
- }();
-
mlir::FlatSymbolRefAttr mapperId;
- if (requiresImplcitMapper) {
+ if (recordType && fir::isRecordWithAllocatableMember(recordType)) {
std::string mapperIdName =
Fortran::utils::openmp::getCanonicalDefaultDeclareMapperName(
recordType);
diff --git a/flang/test/Lower/OpenMP/do_concurrent_nested_derived_type_mapping.f90 b/flang/test/Lower/OpenMP/do_concurrent_nested_derived_type_mapping.f90
new file mode 100644
index 0000000000000..f2e14c27835bb
--- /dev/null
+++ b/flang/test/Lower/OpenMP/do_concurrent_nested_derived_type_mapping.f90
@@ -0,0 +1,87 @@
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fdo-concurrent-to-openmp=device %s -o - \
+! RUN: | FileCheck %s
+
+subroutine nested_dt()
+ implicit none
+
+ type :: buffer
+ integer :: i
+ real :: data(8)
+ end type buffer
+
+ type :: array_dt
+ type(buffer) :: buf
+ end type array_dt
+
+ integer :: i
+ type(array_dt) :: ad
+
+ do concurrent(i=1:8)
+ ad%buf%data(i) = real(i)
+ end do
+end subroutine nested_dt
+
+subroutine nested_alloc_dt()
+ implicit none
+
+ type :: alloc_buffer
+ integer :: i
+ real, allocatable :: data(:)
+ end type alloc_buffer
+
+ type :: alloc_array_dt
+ type(alloc_buffer) :: buf
+ end type alloc_array_dt
+
+ integer :: i
+ type(alloc_array_dt) :: aad
+
+ allocate(aad%buf%data(8), source=0.0)
+
+ do concurrent(i=1:8)
+ aad%buf%data(i) = real(i)
+ end do
+end subroutine nested_alloc_dt
+
+
+! CHECK: omp.declare_mapper @[[BUF_MAPPER:_QFnested_alloc_dtTalloc_buffer_omp_default_mapper]] : !fir.type<_QFnested_alloc_dtTalloc_buffer{i:i32,data:!fir.box<!fir.heap<!fir.array<?xf32>>>}> {
+! CHECK-NEXT: ^bb0(%[[BUF_ARG:.*]]: !fir.ref<!fir.type<_QFnested_alloc_dtTalloc_buffer{i:i32,data:!fir.box<!fir.heap<!fir.array<?xf32>>>}>>):
+! CHECK-NEXT: %[[BUF_DECL:.*]]:2 = hlfir.declare %[[BUF_ARG]] {uniq_name = ""}
+! CHECK: %{{.*}} = fir.field_index i, !fir.type<_QFnested_alloc_dtTalloc_buffer{i:i32,data:!fir.box<!fir.heap<!fir.array<?xf32>>>}>
+! CHECK: %[[I_COORD:.*]] = fir.coordinate_of %[[BUF_DECL]]#0, i : (!fir.ref<!fir.type<_QFnested_alloc_dtTalloc_buffer{i:i32,data:!fir.box<!fir.heap<!fir.array<?xf32>>>}>>) -> !fir.ref<i32>
+! CHECK: %[[BUF_I_MAP:.*]] = omp.map.info var_ptr(%[[I_COORD]] : !fir.ref<i32>, i32) map_clauses(implicit, tofrom) capture(ByRef) name("") -> !fir.ref<i32>
+! CHECK: %{{.*}} = fir.field_index data, !fir.type<_QFnested_alloc_dtTalloc_buffer{i:i32,data:!fir.box<!fir.heap<!fir.array<?xf32>>>}>
+! CHECK: %[[DATA_COORD:.*]] = fir.coordinate_of %[[BUF_DECL]]#0, data : (!fir.ref<!fir.type<_QFnested_alloc_dtTalloc_buffer{i:i32,data:!fir.box<!fir.heap<!fir.array<?xf32>>>}>>) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
+! CHECK: %[[DATA_BOUNDS:.*]] = omp.map.bounds lower_bound({{.*}}) upper_bound({{.*}}) extent({{.*}}) stride({{.*}}) start_idx({{.*}}) stride_in_bytes(true)
+! CHECK: %[[DATA_BASE_PTR:.*]] = fir.box_offset %[[DATA_COORD]] base_addr : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xf32>>>
+! CHECK: %[[BUF_DATA_MAP:.*]] = omp.map.info var_ptr(%[[DATA_COORD]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, !fir.box<!fir.heap<!fir.array<?xf32>>>) map_clauses(implicit, tofrom) capture(ByRef) var_ptr_ptr(%[[DATA_BASE_PTR]] : !fir.llvm_ptr<!fir.ref<!fir.array<?xf32>>>, f32) bounds(%[[DATA_BOUNDS]]) name("") -> !fir.llvm_ptr<!fir.ref<!fir.array<?xf32>>>
+! CHECK: %[[BUF_DESC_MAP:.*]] = omp.map.info var_ptr(%[[DATA_COORD]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, !fir.box<!fir.heap<!fir.array<?xf32>>>) map_clauses(always, implicit, to) capture(ByRef) name("") -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
+! CHECK: %[[BUF_ATTACH_MAP:.*]] = omp.map.info var_ptr(%[[DATA_COORD]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, !fir.box<!fir.heap<!fir.array<?xf32>>>) map_clauses(attach, ref_ptr, ref_ptee) capture(ByRef) var_ptr_ptr(%[[DATA_BASE_PTR]] : !fir.llvm_ptr<!fir.ref<!fir.array<?xf32>>>, f32) bounds(%[[DATA_BOUNDS]]) name("") -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>
+! CHECK: %[[BUF_PARENT_MAP:.*]] = omp.map.info var_ptr(%[[BUF_DECL]]#1 : !fir.ref<!fir.type<_QFnested_alloc_dtTalloc_buffer{i:i32,data:!fir.box<!fir.heap<!fir.array<?xf32>>>}>>, !fir.type<_QFnested_alloc_dtTalloc_buffer{i:i32,data:!fir.box<!fir.heap<!fir.array<?xf32>>>}>) map_clauses(implicit) capture(ByRef) members(%[[BUF_I_MAP]], %[[BUF_DESC_MAP]], %[[BUF_DATA_MAP]] : [0], [1], [1, 0] : !fir.ref<i32>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xf32>>>) name("") partial_map(true) -> !fir.ref<!fir.type<_QFnested_alloc_dtTalloc_buffer{i:i32,data:!fir.box<!fir.heap<!fir.array<?xf32>>>}>>
+! CHECK: omp.declare_mapper.info map_entries(%[[BUF_PARENT_MAP]], %[[BUF_I_MAP]], %[[BUF_DESC_MAP]], %[[BUF_ATTACH_MAP]], %[[BUF_DATA_MAP]] : !fir.ref<!fir.type<_QFnested_alloc_dtTalloc_buffer{i:i32,data:!fir.box<!fir.heap<!fir.array<?xf32>>>}>>, !fir.ref<i32>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xf32>>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xf32>>>)
+
+
+! CHECK: omp.declare_mapper @[[AAD_MAPPER:_QFnested_alloc_dtTalloc_array_dt_omp_default_mapper]] : !fir.type<_QFnested_alloc_dtTalloc_array_dt{buf:!fir.type<_QFnested_alloc_dtTalloc_buffer{i:i32,data:!fir.box<!fir.heap<!fir.array<?xf32>>>}>}> {
+! CHECK-NEXT: ^bb0(%[[AAD_ARG:.*]]: !fir.ref<!fir.type<_QFnested_alloc_dtTalloc_array_dt{buf:!fir.type<_QFnested_alloc_dtTalloc_buffer{i:i32,data:!fir.box<!fir.heap<!fir.array<?xf32>>>}>}>>):
+! CHECK-NEXT: %[[AAD_DECL:.*]]:2 = hlfir.declare %[[AAD_ARG]] {uniq_name = ""}
+! CHECK: %[[AAD_BUF_MAP:.*]] = omp.map.info var_ptr(%{{.*}} : !fir.ref<!fir.type<_QFnested_alloc_dtTalloc_buffer{i:i32,data:!fir.box<!fir.heap<!fir.array<?xf32>>>}>>, !fir.type<_QFnested_alloc_dtTalloc_buffer{i:i32,data:!fir.box<!fir.heap<!fir.array<?xf32>>>}>) map_clauses(implicit, tofrom) capture(ByRef) mapper(@[[BUF_MAPPER]]) name("") -> !fir.ref<!fir.type<_QFnested_alloc_dtTalloc_buffer{i:i32,data:!fir.box<!fir.heap<!fir.array<?xf32>>>}>>
+! CHECK: %[[AAD_PARENT_MAP:.*]] = omp.map.info var_ptr(%[[AAD_DECL]]#1 : !fir.ref<!fir.type<_QFnested_alloc_dtTalloc_array_dt{buf:!fir.type<_QFnested_alloc_dtTalloc_buffer{i:i32,data:!fir.box<!fir.heap<!fir.array<?xf32>>>}>}>>, !fir.type<_QFnested_alloc_dtTalloc_array_dt{buf:!fir.type<_QFnested_alloc_dtTalloc_buffer{i:i32,data:!fir.box<!fir.heap<!fir.array<?xf32>>>}>}>) map_clauses(implicit) capture(ByRef) members(%[[AAD_BUF_MAP]] : [0] : !fir.ref<!fir.type<_QFnested_alloc_dtTalloc_buffer{i:i32,data:!fir.box<!fir.heap<!fir.array<?xf32>>>}>>) name("") partial_map(true) -> !fir.ref<!fir.type<_QFnested_alloc_dtTalloc_array_dt{buf:!fir.type<_QFnested_alloc_dtTalloc_buffer{i:i32,data:!fir.box<!fir.heap<!fir.array<?xf32>>>}>}>>
+! CHECK: omp.declare_mapper.info map_entries(%[[AAD_PARENT_MAP]], %[[AAD_BUF_MAP]] : !fir.ref<!fir.type<_QFnested_alloc_dtTalloc_array_dt{buf:!fir.type<_QFnested_alloc_dtTalloc_buffer{i:i32,data:!fir.box<!fir.heap<!fir.array<?xf32>>>}>}>>, !fir.ref<!fir.type<_QFnested_alloc_dtTalloc_buffer{i:i32,data:!fir.box<!fir.heap<!fir.array<?xf32>>>}>>)
+
+! CHECK-LABEL: func.func @_QPnested_dt() {
+! CHECK: %[[AD_HOST:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFnested_dtEad"} : (!fir.ref<!fir.type<_QFnested_dtTarray_dt{buf:!fir.type<_QFnested_dtTbuffer{i:i32,data:!fir.array<8xf32>}>}>>) -> {{.*}}
+! CHECK: %[[DT_LB:.*]] = omp.map.info var_ptr(%{{.*}} : !fir.ref<index>, index) map_clauses(implicit) capture(ByCopy) name("") -> !fir.ref<index>
+! CHECK: %[[DT_UB:.*]] = omp.map.info var_ptr(%{{.*}} : !fir.ref<index>, index) map_clauses(implicit) capture(ByCopy) name("") -> !fir.ref<index>
+! CHECK: %[[DT_ST:.*]] = omp.map.info var_ptr(%{{.*}} : !fir.ref<index>, index) map_clauses(implicit) capture(ByCopy) name("") -> !fir.ref<index>
+! CHECK: %[[DT_I:.*]] = omp.map.info var_ptr(%{{.*}} : !fir.ref<i32>, i32) map_clauses(implicit) capture(ByCopy) name("_QFnested_dtEi") -> !fir.ref<i32>
+! CHECK: %[[AD_MAP:.*]] = omp.map.info var_ptr(%[[AD_HOST]]#1 : !fir.ref<!fir.type<_QFnested_dtTarray_dt{buf:!fir.type<_QFnested_dtTbuffer{i:i32,data:!fir.array<8xf32>}>}>>, !fir.type<_QFnested_dtTarray_dt{buf:!fir.type<_QFnested_dtTbuffer{i:i32,data:!fir.array<8xf32>}>}>) map_clauses(implicit, tofrom) capture(ByRef) name("_QFnested_dtEad") -> !fir.ref<!fir.type<_QFnested_dtTarray_dt{buf:!fir.type<_QFnested_dtTbuffer{i:i32,data:!fir.array<8xf32>}>}>>
+! CHECK: omp.target kernel_type(spmd) host_eval(%{{.*}} -> %[[DT_A0:.*]], %{{.*}} -> %[[DT_A1:.*]], %{{.*}} -> %[[DT_A2:.*]] : index, index, index) map_entries(%[[DT_LB]] -> %[[DT_MA3:.*]], %[[DT_UB]] -> %[[DT_MA4:.*]], %[[DT_ST]] -> %[[DT_MA5:.*]], %[[DT_I]] -> %[[DT_MA6:.*]], %[[AD_MAP]] -> %[[AD_ARG:.*]] : !fir.ref<index>, !fir.ref<index>, !fir.ref<index>, !fir.ref<i32>, !fir.ref<!fir.type<_QFnested_dtTarray_dt{buf:!fir.type<_QFnested_dtTbuffer{i:i32,data:!fir.array<8xf32>}>}>>) {
+
+! CHECK-LABEL: func.func @_QPnested_alloc_dt() {
+! CHECK: %[[AAD_HOST:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFnested_alloc_dtEaad"} : (!fir.ref<!fir.type<_QFnested_alloc_dtTalloc_array_dt{buf:!fir.type<_QFnested_alloc_dtTalloc_buffer{i:i32,data:!fir.box<!fir.heap<!fir.array<?xf32>>>}>}>>) -> {{.*}}
+! CHECK: %[[AL_LB:.*]] = omp.map.info var_ptr(%{{.*}} : !fir.ref<index>, index) map_clauses(implicit) capture(ByCopy) name("") -> !fir.ref<index>
+! CHECK: %[[AL_UB:.*]] = omp.map.info var_ptr(%{{.*}} : !fir.ref<index>, index) map_clauses(implicit) capture(ByCopy) name("") -> !fir.ref<index>
+! CHECK: %[[AL_ST:.*]] = omp.map.info var_ptr(%{{.*}} : !fir.ref<index>, index) map_clauses(implicit) capture(ByCopy) name("") -> !fir.ref<index>
+! CHECK: %[[AL_I:.*]] = omp.map.info var_ptr(%{{.*}} : !fir.ref<i32>, i32) map_clauses(implicit) capture(ByCopy) name("_QFnested_alloc_dtEi") -> !fir.ref<i32>
+! CHECK: %[[AAD_MAP:.*]] = omp.map.info var_ptr(%[[AAD_HOST]]#1 : !fir.ref<!fir.type<_QFnested_alloc_dtTalloc_array_dt{buf:!fir.type<_QFnested_alloc_dtTalloc_buffer{i:i32,data:!fir.box<!fir.heap<!fir.array<?xf32>>>}>}>>, !fir.type<_QFnested_alloc_dtTalloc_array_dt{buf:!fir.type<_QFnested_alloc_dtTalloc_buffer{i:i32,data:!fir.box<!fir.heap<!fir.array<?xf32>>>}>}>) map_clauses(implicit, tofrom) capture(ByRef) mapper(@[[AAD_MAPPER]]) name("_QFnested_alloc_dtEaad") -> !fir.ref<!fir.type<_QFnested_alloc_dtTalloc_array_dt{buf:!fir.type<_QFnested_alloc_dtTalloc_buffer{i:i32,data:!fir.box<!fir.heap<!fir.array<?xf32>>>}>}>>
+! CHECK: omp.target kernel_type(spmd) host_eval(%{{.*}} -> %[[AL_A0:.*]], %{{.*}} -> %[[AL_A1:.*]], %{{.*}} -> %[[AL_A2:.*]] : index, index, index) map_entries(%[[AL_LB]] -> %[[AL_MA3:.*]], %[[AL_UB]] -> %[[AL_MA4:.*]], %[[AL_ST]] -> %[[AL_MA5:.*]], %[[AL_I]] -> %[[AL_MA6:.*]], %[[AAD_MAP]] -> %[[AAD_ARG:.*]] : !fir.ref<index>, !fir.ref<index>, !fir.ref<index>, !fir.ref<i32>, !fir.ref<!fir.type<_QFnested_alloc_dtTalloc_array_dt{buf:!fir.type<_QFnested_alloc_dtTalloc_buffer{i:i32,data:!fir.box<!fir.heap<!fir.array<?xf32>>>}>}>>) {
diff --git a/offload/test/offloading/fortran/do-concurrent-to-omp-nested-derived-type.f90 b/offload/test/offloading/fortran/do-concurrent-to-omp-nested-derived-type.f90
new file mode 100644
index 0000000000000..886c68f7e89bd
--- /dev/null
+++ b/offload/test/offloading/fortran/do-concurrent-to-omp-nested-derived-type.f90
@@ -0,0 +1,50 @@
+! Verifies that `do concurrent` correctly lowers map for basic nested derived
+! types, correctly mapping the required components of the derived type.
+! REQUIRES: flang, amdgpu
+
+! RUN: %libomptarget-compile-fortran-generic -fdo-concurrent-to-openmp=device
+! RUN: %libomptarget-run-generic 2>&1 | %fcheck-generic
+program main
+ implicit none
+
+ type :: alloc_buffer
+ integer :: i
+ real, allocatable :: data(:)
+ end type alloc_buffer
+
+ type :: buffer
+ integer :: i
+ real :: data(8)
+ end type buffer
+
+ type :: array_dt
+ type(buffer) :: buf
+ end type array_dt
+
+ type :: alloc_array_dt
+ type(alloc_buffer) :: buf
+ end type alloc_array_dt
+
+ integer, parameter :: n = 8
+ integer :: i
+ type(alloc_array_dt) :: aad
+ type(array_dt) :: ad
+
+ allocate(aad%buf%data(n), source=0.0)
+
+ do concurrent(i=1:n)
+ aad%buf%data(i) = real(i)
+ end do
+
+ do concurrent(i=1:n)
+ ad%buf%data(i) = real(i)
+ end do
+
+ print *, sum(ad%buf%data)
+ print *, sum(aad%buf%data)
+
+ deallocate(aad%buf%data)
+end program main
+
+! CHECK: 36.
+! CHECK: 36.
More information about the flang-commits
mailing list