[llvm-branch-commits] [flang] [llvm] [mlir] [Flang][OpenMP] Derived type explicit allocatable member mapping (PR #113557)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Thu Nov 7 20:25:19 PST 2024
https://github.com/agozillon updated https://github.com/llvm/llvm-project/pull/113557
>From 17f5b48340e1b24146c8410e3c1e83a5e8aca2fa Mon Sep 17 00:00:00 2001
From: agozillon <Andrew.Gozillon at amd.com>
Date: Fri, 4 Oct 2024 12:59:06 -0500
Subject: [PATCH 1/3] [OpenMP] Allocatable explicit member mapping fortran
offloading tests
This PR is one in a series of 3 that aim to add support for explicit member mapping of
allocatable components in derived types within OpenMP+Fortran for Flang.
This PR provides all of the runtime tests that are currently upstreamable, unfortunately
some of the other tests would require linking of the fortran runtime for offload which
we currently do not do. But regardless, this is plenty to ensure that the mapping is
working in most cases.
---
.../basic-target-region-1D-array-section.f90 | 4 +-
.../basic-target-region-3D-array-section.f90 | 4 +-
.../fortran/basic-target-region-3D-array.f90 | 4 +-
.../offloading/fortran/constant-arr-index.f90 | 6 +-
.../declare-target-vars-in-target-region.f90 | 6 +-
...double-target-call-with-declare-target.f90 | 7 +-
.../dtype-array-constant-index-map.f90 | 20 +-
.../fortran/dtype-member-map-syntax-1.f90 | 109 +++++++++++
.../fortran/dtype-member-map-syntax-2.f90 | 176 ++++++++++++++++++
.../offloading/fortran/dump_map_tables.f90 | 6 +-
.../fortran/local-descriptor-map-regress.f90 | 24 +--
.../test/offloading/fortran/target-depend.f90 | 3 +-
.../target-map-all-common-block-members.f90 | 5 +-
...map-alloca-dtype-alloca-array-of-dtype.f90 | 36 ++++
.../target-map-alloca-dtype-alloca-array.f90 | 29 +++
...t-map-alloca-dtype-and-alloca-array-v2.f90 | 34 ++++
...rget-map-alloca-dtype-and-alloca-array.f90 | 33 ++++
...rget-map-alloca-dtype-array-and-scalar.f90 | 39 ++++
...target-map-alloca-dtype-array-of-dtype.f90 | 35 ++++
...ap-allocatable-array-section-1d-bounds.f90 | 5 +-
...ap-allocatable-array-section-3d-bounds.f90 | 5 +-
.../fortran/target-map-allocatable-dtype.f90 | 31 +++
.../target-map-allocatable-map-scopes.f90 | 4 +-
.../fortran/target-map-common-block.f90 | 5 +-
...t-map-declare-target-link-common-block.f90 | 6 +-
.../target-map-derived-type-full-1.f90 | 6 +-
.../target-map-derived-type-full-2.f90 | 5 +-
...arget-map-derived-type-full-implicit-1.f90 | 6 +-
...arget-map-derived-type-full-implicit-2.f90 | 6 +-
...double-large-nested-dtype-multi-member.f90 | 5 +-
...t-map-double-nested-dtype-array-bounds.f90 | 5 +-
...ouble-nested-dtype-double-array-bounds.f90 | 5 +-
...-map-double-nested-dtype-single-member.f90 | 5 +-
...-map-dtype-3d-alloca-array-with-bounds.f90 | 41 ++++
...-map-dtype-alloca-and-non-alloca-array.f90 | 36 ++++
...type-alloca-array-and-non-alloca-dtype.f90 | 44 +++++
...target-map-dtype-alloca-array-of-dtype.f90 | 34 ++++
...get-map-dtype-alloca-array-with-bounds.f90 | 29 +++
.../target-map-dtype-allocatable-array.f90 | 28 +++
...map-dtype-allocatable-scalar-and-array.f90 | 34 ++++
...pe-arr-bounds-member-enter-exit-update.f90 | 8 +-
...map-dtype-arr-bounds-member-enter-exit.f90 | 8 +-
...dtype-explicit-individual-array-member.f90 | 5 +-
...-multi-explicit-array-3D-member-bounds.f90 | 6 +-
...ype-multi-explicit-array-member-bounds.f90 | 6 +-
...-map-dtype-multi-explicit-array-member.f90 | 5 +-
...target-map-dtype-multi-explicit-member.f90 | 5 +-
.../target-map-enter-exit-allocatables.f90 | 4 +-
.../fortran/target-map-enter-exit-array-2.f90 | 4 +-
.../target-map-enter-exit-array-bounds.f90 | 5 +-
.../fortran/target-map-enter-exit-array.f90 | 4 +-
.../fortran/target-map-enter-exit-scalar.f90 | 3 +-
.../target-map-first-common-block-member.f90 | 5 +-
...target-map-individual-dtype-member-map.f90 | 5 +-
...et-map-large-nested-dtype-multi-member.f90 | 5 +-
...t-map-mix-imp-exp-common-block-members.f90 | 6 +-
...lloca-dtypes-with-multi-alloca-members.f90 | 90 +++++++++
...alloca-dtypes-with-multi-mixed-members.f90 | 82 ++++++++
...ed-alloca-dtype-3d-alloca-array-bounds.f90 | 51 +++++
...ested-alloca-dtype-alloca-array-bounds.f90 | 43 +++++
...sted-dtype-3d-alloca-array-with-bounds.f90 | 50 +++++
...sted-dtype-alloca-and-non-alloca-array.f90 | 47 +++++
...type-alloca-array-and-non-alloca-dtype.f90 | 51 +++++
...-nested-dtype-alloca-array-with-bounds.f90 | 43 +++++
.../target-map-nested-dtype-alloca-array.f90 | 37 ++++
...target-map-nested-dtype-complex-member.f90 | 5 +-
...target-map-nested-dtype-derived-member.f90 | 6 +-
.../target-map-nested-dtype-multi-member.f90 | 5 +-
.../target-map-nested-dtype-single-member.f90 | 5 +-
.../target-map-pointer-scopes-enter-exit.f90 | 4 +-
...pointer-target-array-section-3d-bounds.f90 | 5 +-
.../target-map-pointer-target-scopes.f90 | 4 +-
...ap-pointer-to-dtype-allocatable-member.f90 | 45 +++++
.../target-map-second-common-block-member.f90 | 5 +-
.../target-map-two-dtype-explicit-member.f90 | 5 +-
...type-individual-member-array-1D-bounds.f90 | 6 +-
...type-mixed-implicit-explicit-capture-1.f90 | 5 +-
...type-mixed-implicit-explicit-capture-2.f90 | 6 +-
...two-dtype-multi-member-array-1D-bounds.f90 | 6 +-
...-map-two-nested-dtype-member-array-map.f90 | 4 +-
.../fortran/target-nested-target-data.f90 | 3 +-
.../fortran/target-region-implicit-array.f90 | 4 +-
82 files changed, 1433 insertions(+), 193 deletions(-)
create mode 100644 offload/test/offloading/fortran/dtype-member-map-syntax-1.f90
create mode 100644 offload/test/offloading/fortran/dtype-member-map-syntax-2.f90
create mode 100644 offload/test/offloading/fortran/target-map-alloca-dtype-alloca-array-of-dtype.f90
create mode 100644 offload/test/offloading/fortran/target-map-alloca-dtype-alloca-array.f90
create mode 100644 offload/test/offloading/fortran/target-map-alloca-dtype-and-alloca-array-v2.f90
create mode 100644 offload/test/offloading/fortran/target-map-alloca-dtype-and-alloca-array.f90
create mode 100644 offload/test/offloading/fortran/target-map-alloca-dtype-array-and-scalar.f90
create mode 100644 offload/test/offloading/fortran/target-map-alloca-dtype-array-of-dtype.f90
create mode 100644 offload/test/offloading/fortran/target-map-allocatable-dtype.f90
create mode 100644 offload/test/offloading/fortran/target-map-dtype-3d-alloca-array-with-bounds.f90
create mode 100644 offload/test/offloading/fortran/target-map-dtype-alloca-and-non-alloca-array.f90
create mode 100644 offload/test/offloading/fortran/target-map-dtype-alloca-array-and-non-alloca-dtype.f90
create mode 100644 offload/test/offloading/fortran/target-map-dtype-alloca-array-of-dtype.f90
create mode 100644 offload/test/offloading/fortran/target-map-dtype-alloca-array-with-bounds.f90
create mode 100644 offload/test/offloading/fortran/target-map-dtype-allocatable-array.f90
create mode 100644 offload/test/offloading/fortran/target-map-dtype-allocatable-scalar-and-array.f90
create mode 100644 offload/test/offloading/fortran/target-map-multi-alloca-dtypes-with-multi-alloca-members.f90
create mode 100644 offload/test/offloading/fortran/target-map-multi-alloca-dtypes-with-multi-mixed-members.f90
create mode 100644 offload/test/offloading/fortran/target-map-nested-alloca-dtype-3d-alloca-array-bounds.f90
create mode 100644 offload/test/offloading/fortran/target-map-nested-alloca-dtype-alloca-array-bounds.f90
create mode 100644 offload/test/offloading/fortran/target-map-nested-dtype-3d-alloca-array-with-bounds.f90
create mode 100644 offload/test/offloading/fortran/target-map-nested-dtype-alloca-and-non-alloca-array.f90
create mode 100644 offload/test/offloading/fortran/target-map-nested-dtype-alloca-array-and-non-alloca-dtype.f90
create mode 100644 offload/test/offloading/fortran/target-map-nested-dtype-alloca-array-with-bounds.f90
create mode 100644 offload/test/offloading/fortran/target-map-nested-dtype-alloca-array.f90
create mode 100644 offload/test/offloading/fortran/target-map-pointer-to-dtype-allocatable-member.f90
diff --git a/offload/test/offloading/fortran/basic-target-region-1D-array-section.f90 b/offload/test/offloading/fortran/basic-target-region-1D-array-section.f90
index 15795fbcf7f354..61244a965a1b88 100644
--- a/offload/test/offloading/fortran/basic-target-region-1D-array-section.f90
+++ b/offload/test/offloading/fortran/basic-target-region-1D-array-section.f90
@@ -1,5 +1,5 @@
-! Basic offloading test of arrays with provided lower
-! and upper bounds as specified by OpenMP's sectioning
+! Basic offloading test of arrays with provided lower and upper bounds as
+! specified by OpenMP's sectioning
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/basic-target-region-3D-array-section.f90 b/offload/test/offloading/fortran/basic-target-region-3D-array-section.f90
index ca0364543c20f8..2e1c6a61379c3f 100644
--- a/offload/test/offloading/fortran/basic-target-region-3D-array-section.f90
+++ b/offload/test/offloading/fortran/basic-target-region-3D-array-section.f90
@@ -1,5 +1,5 @@
-! Basic offloading test of a regular array explicitly
-! passed within a target region
+! Basic offloading test of a regular array explicitly passed within a target
+! region
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/basic-target-region-3D-array.f90 b/offload/test/offloading/fortran/basic-target-region-3D-array.f90
index d575810713895e..61fced35980f41 100644
--- a/offload/test/offloading/fortran/basic-target-region-3D-array.f90
+++ b/offload/test/offloading/fortran/basic-target-region-3D-array.f90
@@ -1,5 +1,5 @@
-! Basic offloading test of a regular array explicitly
-! passed within a target region
+! Basic offloading test of a regular array explicitly passed within a target
+! region
! REQUIRES: flang
! REQUIRES: gpu
! UNSUPPORTED: nvptx64-nvidia-cuda-LTO
diff --git a/offload/test/offloading/fortran/constant-arr-index.f90 b/offload/test/offloading/fortran/constant-arr-index.f90
index 80440b6836ac8a..f819f1f0d994df 100644
--- a/offload/test/offloading/fortran/constant-arr-index.f90
+++ b/offload/test/offloading/fortran/constant-arr-index.f90
@@ -1,7 +1,5 @@
-! Basic offloading test with a target region
-! that checks constant indexing on device
-! correctly works (regression test for prior
-! bug).
+! Basic offloading test with a target region that checks constant indexing on
+! device correctly works (regression test for prior bug).
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/declare-target-vars-in-target-region.f90 b/offload/test/offloading/fortran/declare-target-vars-in-target-region.f90
index c0bc9304b3030d..5410a0681e8e2a 100644
--- a/offload/test/offloading/fortran/declare-target-vars-in-target-region.f90
+++ b/offload/test/offloading/fortran/declare-target-vars-in-target-region.f90
@@ -1,6 +1,6 @@
-! Offloading test with a target region mapping a declare target
-! Fortran array writing some values to it and checking the host
-! correctly receives the updates made on the device.
+! Offloading test with a target region mapping a declare target Fortran array
+! writing some values to it and checking the host correctly receives the
+! updates made on the device.
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/double-target-call-with-declare-target.f90 b/offload/test/offloading/fortran/double-target-call-with-declare-target.f90
index fa909815757f92..f7fef9583214bd 100644
--- a/offload/test/offloading/fortran/double-target-call-with-declare-target.f90
+++ b/offload/test/offloading/fortran/double-target-call-with-declare-target.f90
@@ -1,7 +1,6 @@
-! Offloading test with two target regions mapping the same
-! declare target Fortran array and writing some values to
-! it before checking the host correctly receives the
-! correct updates made on the device.
+! Offloading test with two target regions mapping the same declare target
+! Fortran array and writing some values to it before checking the host
+! correctly receives the correct updates made on the device.
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/dtype-array-constant-index-map.f90 b/offload/test/offloading/fortran/dtype-array-constant-index-map.f90
index 7e168b846f858c..e120c95019c602 100644
--- a/offload/test/offloading/fortran/dtype-array-constant-index-map.f90
+++ b/offload/test/offloading/fortran/dtype-array-constant-index-map.f90
@@ -1,17 +1,9 @@
-! Offloading test which maps a specific element of a
-! derived type to the device and then accesses the
-! element alongside an individual element of an array
-! that the derived type contains. In particular, this
-! test helps to check that we can replace the constants
-! within the kernel with instructions and then replace
-! these instructions with the kernel parameters.
-! REQUIRES: flang
-! UNSUPPORTED: nvptx64-nvidia-cuda
-! UNSUPPORTED: nvptx64-nvidia-cuda-LTO
-! UNSUPPORTED: aarch64-unknown-linux-gnu
-! UNSUPPORTED: aarch64-unknown-linux-gnu-LTO
-! UNSUPPORTED: x86_64-unknown-linux-gnu
-! UNSUPPORTED: x86_64-unknown-linux-gnu-LTO
+! Offloading test which maps a specific element of a derived type to the device
+! and then accesses the element alongside an individual element of an array
+! that the derived type contains. In particular, this test helps to check that
+! we can replace the constants within the kernel with instructions and then
+! replace these instructions with the kernel parameters.
+! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
module test_0
diff --git a/offload/test/offloading/fortran/dtype-member-map-syntax-1.f90 b/offload/test/offloading/fortran/dtype-member-map-syntax-1.f90
new file mode 100644
index 00000000000000..fa4f20149c017e
--- /dev/null
+++ b/offload/test/offloading/fortran/dtype-member-map-syntax-1.f90
@@ -0,0 +1,109 @@
+! This test checks a number of more complex derived type member mapping
+! syntaxes utilising a non-allocatable parent derived type.
+
+! REQUIRES: flang, amdgpu
+
+! RUN: %libomptarget-compile-fortran-run-and-check-generic
+program main
+ type dtype2
+ integer int
+ real float
+ real float_elements(10)
+ end type dtype2
+
+ type dtype1
+ character (LEN=30) characters
+ character (LEN=1) character
+ type(dtype2) number
+ end type dtype1
+
+ type nonallocatabledtype
+ integer elements(20)
+ type(dtype1) num_chars
+ integer value
+ type(dtype2) internal_dtypes(5)
+ end type nonallocatabledtype
+
+ type (nonallocatabledtype) array_dtype(5)
+
+ !$omp target map(tofrom: array_dtype(5))
+ do i = 1, 20
+ array_dtype(5)%elements(i) = 20 + i
+ end do
+
+ array_dtype(5)%num_chars%number%float_elements(5) = 10
+ array_dtype(5)%value = 40
+ !$omp end target
+
+ print *, array_dtype(5)%elements
+ print *, array_dtype(5)%num_chars%number%float_elements(5)
+ print *, array_dtype(5)%value
+
+ !$omp target map(tofrom: array_dtype(4)%elements(3))
+ array_dtype(4)%elements(3) = 74
+ !$omp end target
+
+ print *, array_dtype(4)%elements(3)
+
+ !$omp target map(tofrom: array_dtype(5)%elements(3:5))
+ do i = 3, 5
+ array_dtype(5)%elements(i) = i + 1
+ end do
+ !$omp end target
+
+ do i = 3, 5
+ print *, array_dtype(5)%elements(i)
+ end do
+
+ !$omp target map(tofrom: array_dtype(3:5))
+ do i = 3, 5
+ array_dtype(i)%value = i + 2
+ end do
+ !$omp end target
+
+ do i = 3, 5
+ print *, array_dtype(i)%value
+ end do
+
+ !$omp target map(tofrom: array_dtype(4)%num_chars%number%float_elements(8))
+ array_dtype(4)%num_chars%number%float_elements(8) = 250
+ !$omp end target
+
+ print *, array_dtype(4)%num_chars%number%float_elements(8)
+
+ !$omp target map(tofrom: array_dtype(4)%num_chars%number%float_elements(5:10))
+ do i = 5, 10
+ array_dtype(4)%num_chars%number%float_elements(i) = i + 3
+ end do
+ !$omp end target
+
+ do i = 5, 10
+ print *, array_dtype(4)%num_chars%number%float_elements(i)
+ end do
+
+ !$omp target map(tofrom: array_dtype(4)%internal_dtypes(3)%float_elements(4))
+ array_dtype(4)%internal_dtypes(3)%float_elements(4) = 200
+ !$omp end target
+
+ print *, array_dtype(4)%internal_dtypes(3)%float_elements(4)
+
+end program main
+
+! CHECK: 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
+! CHECK: 10.
+! CHECK: 40
+! CHECK: 74
+! CHECK: 4
+! CHECK: 5
+! CHECK: 6
+! CHECK: 5
+! CHECK: 6
+! CHECK: 7
+! CHECK: 250.
+! CHECK: 8.
+! CHECK: 9.
+! CHECK: 10.
+! CHECK: 11.
+! CHECK: 12.
+! CHECK: 13.
+! CHECK: 200
diff --git a/offload/test/offloading/fortran/dtype-member-map-syntax-2.f90 b/offload/test/offloading/fortran/dtype-member-map-syntax-2.f90
new file mode 100644
index 00000000000000..8d666360066d9b
--- /dev/null
+++ b/offload/test/offloading/fortran/dtype-member-map-syntax-2.f90
@@ -0,0 +1,176 @@
+! This test checks a number of more complex derived type member mapping
+! syntaxes utilising an allocatable parent derived type and mixed
+! allocatable members.
+
+! REQUIRES: flang, amdgpu
+
+! RUN: %libomptarget-compile-fortran-run-and-check-generic
+program main
+ implicit none
+
+ integer :: i
+ integer :: N1, N2
+
+ type :: vertexes
+ integer :: test
+ integer :: testarray(10)
+ integer(4), allocatable :: vertexx(:)
+ integer(4), allocatable :: vertexy(:)
+ end type vertexes
+
+ type testing_tile_type
+ TYPE(vertexes) :: field
+ end type testing_tile_type
+
+ type :: dtype
+ real(4) :: i
+ type(vertexes), allocatable :: vertexes(:)
+ TYPE(testing_tile_type), DIMENSION(:), allocatable :: test_tile
+ integer(4) :: array_i(10)
+ real(4) :: j
+ integer, allocatable :: array_j(:)
+ integer(4) :: k
+ end type dtype
+
+ type(dtype) :: alloca_dtype
+ type(dtype), DIMENSION(:), allocatable :: alloca_dtype_arr
+
+ allocate(alloca_dtype%vertexes(4))
+ allocate(alloca_dtype%vertexes(1)%vertexx(10))
+ allocate(alloca_dtype%vertexes(1)%vertexy(10))
+ allocate(alloca_dtype%vertexes(2)%vertexx(10))
+ allocate(alloca_dtype%vertexes(2)%vertexy(10))
+ allocate(alloca_dtype%vertexes(3)%vertexx(10))
+ allocate(alloca_dtype%vertexes(3)%vertexy(10))
+ allocate(alloca_dtype%vertexes(4)%vertexx(10))
+ allocate(alloca_dtype%vertexes(4)%vertexy(10))
+ allocate(alloca_dtype%test_tile(4))
+ allocate(alloca_dtype%test_tile(1)%field%vertexx(10))
+ allocate(alloca_dtype%test_tile(1)%field%vertexy(10))
+ allocate(alloca_dtype%test_tile(2)%field%vertexx(10))
+ allocate(alloca_dtype%test_tile(2)%field%vertexy(10))
+ allocate(alloca_dtype%test_tile(3)%field%vertexx(10))
+ allocate(alloca_dtype%test_tile(3)%field%vertexy(10))
+ allocate(alloca_dtype%test_tile(4)%field%vertexx(10))
+ allocate(alloca_dtype%test_tile(4)%field%vertexy(10))
+
+ allocate(alloca_dtype_arr(3))
+
+ N1 = 1
+ N2 = 2
+
+!$omp target map(tofrom: alloca_dtype%vertexes(N1)%test)
+ alloca_dtype%vertexes(N1)%test = 3
+!$omp end target
+
+print *, alloca_dtype%vertexes(N1)%test
+
+!$omp target map(tofrom: alloca_dtype%vertexes(N1)%test, alloca_dtype%vertexes(N2)%test)
+ alloca_dtype%vertexes(N1)%test = 5
+ alloca_dtype%vertexes(N2)%test = 10
+!$omp end target
+
+print *, alloca_dtype%vertexes(N1)%test
+print *, alloca_dtype%vertexes(N2)%test
+
+!$omp target map(tofrom: alloca_dtype%test_tile(N1)%field%vertexx, &
+!$omp alloca_dtype%test_tile(N1)%field%vertexy)
+ do i = 1, 10
+ alloca_dtype%test_tile(N1)%field%vertexx(i) = i + 4
+ alloca_dtype%test_tile(N1)%field%vertexy(i) = i + 4
+ end do
+!$omp end target
+
+print *, alloca_dtype%test_tile(N1)%field%vertexx
+print *, alloca_dtype%test_tile(N1)%field%vertexy
+
+!$omp target map(tofrom: alloca_dtype%test_tile(N1)%field%test, &
+!$omp alloca_dtype%test_tile(N2)%field%test, &
+!$omp alloca_dtype%test_tile(N1)%field%vertexy, &
+!$omp alloca_dtype%test_tile(N2)%field%vertexy)
+ alloca_dtype%test_tile(N2)%field%test = 9999
+ alloca_dtype%test_tile(N2)%field%vertexy(2) = 9998
+ alloca_dtype%test_tile(N1)%field%test = 9997
+ alloca_dtype%test_tile(N1)%field%vertexy(2) = 9996
+!$omp end target
+
+print *, alloca_dtype%test_tile(N1)%field%test
+print *, alloca_dtype%test_tile(N2)%field%test
+print *, alloca_dtype%test_tile(N1)%field%vertexy(2)
+print *, alloca_dtype%test_tile(N2)%field%vertexy(2)
+
+!$omp target map(tofrom: alloca_dtype%test_tile(N2)%field%vertexy)
+ alloca_dtype%test_tile(N2)%field%vertexy(2) = 2000
+!$omp end target
+
+!$omp target map(tofrom: alloca_dtype%vertexes(N1)%vertexx, &
+!$omp alloca_dtype%vertexes(N1)%vertexy, &
+!$omp alloca_dtype%vertexes(N2)%vertexx, &
+!$omp alloca_dtype%vertexes(N2)%vertexy)
+ do i = 1, 10
+ alloca_dtype%vertexes(N1)%vertexx(i) = i * 2
+ alloca_dtype%vertexes(N1)%vertexy(i) = i * 2
+ alloca_dtype%vertexes(N2)%vertexx(i) = i * 2
+ alloca_dtype%vertexes(N2)%vertexy(i) = i * 2
+ end do
+!$omp end target
+
+print *, alloca_dtype%vertexes(N1)%vertexx
+print *, alloca_dtype%vertexes(N1)%vertexy
+print *, alloca_dtype%vertexes(N2)%vertexx
+print *, alloca_dtype%vertexes(N2)%vertexy
+
+!$omp target map(tofrom: alloca_dtype%vertexes(N1)%vertexx, &
+!$omp alloca_dtype%vertexes(N1)%vertexy, &
+!$omp alloca_dtype%vertexes(4)%vertexy, &
+!$omp alloca_dtype%vertexes(4)%vertexx, &
+!$omp alloca_dtype%vertexes(N2)%vertexx, &
+!$omp alloca_dtype%vertexes(N2)%vertexy)
+ do i = 1, 10
+ alloca_dtype%vertexes(N1)%vertexx(i) = i * 3
+ alloca_dtype%vertexes(N1)%vertexy(i) = i * 3
+ alloca_dtype%vertexes(4)%vertexx(i) = i * 3
+ alloca_dtype%vertexes(4)%vertexy(i) = i * 3
+ alloca_dtype%vertexes(N2)%vertexx(i) = i * 3
+ alloca_dtype%vertexes(N2)%vertexy(i) = i * 3
+ end do
+!$omp end target
+
+
+ print *, alloca_dtype%vertexes(1)%vertexx
+ print *, alloca_dtype%vertexes(1)%vertexy
+ print *, alloca_dtype%vertexes(4)%vertexx
+ print *, alloca_dtype%vertexes(4)%vertexy
+ print *, alloca_dtype%vertexes(2)%vertexx
+ print *, alloca_dtype%vertexes(2)%vertexy
+
+!$omp target map(tofrom: alloca_dtype_arr(N2)%array_i)
+ do i = 1, 10
+ alloca_dtype_arr(N2)%array_i(i) = i + 2
+ end do
+!$omp end target
+
+print *, alloca_dtype_arr(N2)%array_i
+
+end program main
+
+! CHECK: 3
+! CHECK: 5
+! CHECK: 10
+! CHECK: 5 6 7 8 9 10 11 12 13 14
+! CHECK: 5 6 7 8 9 10 11 12 13 14
+! CHECK: 9997
+! CHECK: 9999
+! CHECK: 9996
+! CHECK: 9998
+! CHECK: 2 4 6 8 10 12 14 16 18 20
+! CHECK: 2 4 6 8 10 12 14 16 18 20
+! CHECK: 2 4 6 8 10 12 14 16 18 20
+! CHECK: 2 4 6 8 10 12 14 16 18 20
+! CHECK: 3 6 9 12 15 18 21 24 27 30
+! CHECK: 3 6 9 12 15 18 21 24 27 30
+! CHECK: 3 6 9 12 15 18 21 24 27 30
+! CHECK: 3 6 9 12 15 18 21 24 27 30
+! CHECK: 3 6 9 12 15 18 21 24 27 30
+! CHECK: 3 6 9 12 15 18 21 24 27 30
+! CHECK: 3 4 5 6 7 8 9 10 11 12
diff --git a/offload/test/offloading/fortran/dump_map_tables.f90 b/offload/test/offloading/fortran/dump_map_tables.f90
index e25b05b9e04db5..efde4ee56ca1a0 100644
--- a/offload/test/offloading/fortran/dump_map_tables.f90
+++ b/offload/test/offloading/fortran/dump_map_tables.f90
@@ -1,6 +1,6 @@
-! Offloading test with runtine call to ompx_dump_mapping_tables
-! Fortran array writing some values and printing the variable mapped to device
-! correctly receives the updates made on the device.
+! Offloading test with runtine call to ompx_dump_mapping_tables Fortran array
+! writing some values and printing the variable mapped to device correctly
+! receives the updates made on the device.
! REQUIRES: flang
! UNSUPPORTED: nvptx64-nvidia-cuda-LTO
! UNSUPPORTED: aarch64-unknown-linux-gnu
diff --git a/offload/test/offloading/fortran/local-descriptor-map-regress.f90 b/offload/test/offloading/fortran/local-descriptor-map-regress.f90
index 5f628b8ad8c7af..e6afc4a6fb9b1a 100644
--- a/offload/test/offloading/fortran/local-descriptor-map-regress.f90
+++ b/offload/test/offloading/fortran/local-descriptor-map-regress.f90
@@ -1,17 +1,13 @@
-! Small regression test that checks that we do not cause
-! a runtime map error in cases where we are required to
-! allocate a local variable for the fortran descriptor
-! to store into and then load from it, done so by
-! re-using the temporary local variable across all
-! maps related to the mapped variable and associated
-! local variable to make sure that each map does as
-! it's intended to do with the original data. This
-! prevents blobs of local descriptor data remaining
-! attatched on device long after it's supposed to,
-! which can cause weird map issues later in susbequent
-! function invocations. However, it doesn't avoid a user
-! shooting themselves in the foot by mapping data via enter
-! and then not providing a corresponding exit.
+! Small regression test that checks that we do not cause a runtime map error in
+! cases where we are required to allocate a local variable for the fortran
+! descriptor to store into and then load from it, done so by re-using the
+! temporary local variable across all maps related to the mapped variable and
+! associated local variable to make sure that each map does as it is intended
+! to do with the original data. This prevents blobs of local descriptor data
+! remaining attatched on device long after it's supposed to, which can cause
+! weird map issues later in susbequent function invocations. However, it
+! doesn't avoid a user shooting themselves in the foot by mapping data via
+! enter and then not providing a corresponding exit.
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/target-depend.f90 b/offload/test/offloading/fortran/target-depend.f90
index 1bb320d6bd93c1..dc9351dd8c20af 100644
--- a/offload/test/offloading/fortran/target-depend.f90
+++ b/offload/test/offloading/fortran/target-depend.f90
@@ -1,5 +1,4 @@
-! Offloading test checking the use of the depend clause on
-! the target construct
+! Offloading test checking the use of the depend clause on the target construct
! REQUIRES: flang, amdgcn-amd-amdhsa
! UNSUPPORTED: nvptx64-nvidia-cuda
! UNSUPPORTED: nvptx64-nvidia-cuda-LTO
diff --git a/offload/test/offloading/fortran/target-map-all-common-block-members.f90 b/offload/test/offloading/fortran/target-map-all-common-block-members.f90
index f92e5818a76405..4e78ed1accf3ed 100644
--- a/offload/test/offloading/fortran/target-map-all-common-block-members.f90
+++ b/offload/test/offloading/fortran/target-map-all-common-block-members.f90
@@ -1,6 +1,5 @@
-! Offloading test checking interaction of
-! mapping all the members of a common block
-! to a target region
+! Offloading test checking interaction of mapping all the members of a common
+! block to a target region
! REQUIRES: flang, amdgcn-amd-amdhsa
! UNSUPPORTED: nvptx64-nvidia-cuda
! UNSUPPORTED: nvptx64-nvidia-cuda-LTO
diff --git a/offload/test/offloading/fortran/target-map-alloca-dtype-alloca-array-of-dtype.f90 b/offload/test/offloading/fortran/target-map-alloca-dtype-alloca-array-of-dtype.f90
new file mode 100644
index 00000000000000..c430726cfbe93a
--- /dev/null
+++ b/offload/test/offloading/fortran/target-map-alloca-dtype-alloca-array-of-dtype.f90
@@ -0,0 +1,36 @@
+! Offloading test checking interaction of explicit member mapping of an
+! allocatable array of derived types contained within an allocatable
+! derived type
+! REQUIRES: flang, amdgpu
+
+! RUN: %libomptarget-compile-fortran-run-and-check-generic
+program main
+ type :: nested_dtype
+ real(4) :: i
+ real(4) :: j
+ integer(4) :: array_i(10)
+ integer(4) :: k
+ end type nested_dtype
+
+ type :: dtype
+ real(4) :: i
+ integer(4) :: array_i(10)
+ real(4) :: j
+ type(nested_dtype), allocatable :: array_dtype(:)
+ integer(4) :: k
+ end type dtype
+
+ type(dtype), allocatable :: dtyped
+ allocate(dtyped)
+ allocate(dtyped%array_dtype(10))
+
+!$omp target map(tofrom: dtyped%array_dtype)
+ do i = 1, 10
+ dtyped%array_dtype(i)%k = i
+ end do
+!$omp end target
+
+ print *, dtyped%array_dtype%k
+end program main
+
+!CHECK: 1 2 3 4 5 6 7 8 9 10
diff --git a/offload/test/offloading/fortran/target-map-alloca-dtype-alloca-array.f90 b/offload/test/offloading/fortran/target-map-alloca-dtype-alloca-array.f90
new file mode 100644
index 00000000000000..df51128fc5b7d8
--- /dev/null
+++ b/offload/test/offloading/fortran/target-map-alloca-dtype-alloca-array.f90
@@ -0,0 +1,29 @@
+! Offload test that checks an allocatable array within an allocatable derived
+! type can be mapped explicitly using member mapping.
+! REQUIRES: flang, amdgpu
+
+! RUN: %libomptarget-compile-fortran-run-and-check-generic
+program main
+ type :: dtype
+ real(4) :: i
+ integer(4) :: array_i(10)
+ real(4) :: j
+ integer, allocatable :: array_j(:)
+ integer(4) :: k
+ end type dtype
+
+ type(dtype), allocatable :: alloca_dtype
+ allocate(alloca_dtype)
+ allocate(alloca_dtype%array_j(10))
+
+!$omp target map(tofrom: alloca_dtype%array_j)
+ do i = 1, 10
+ alloca_dtype%array_j(i) = i
+ end do
+!$omp end target
+
+print *, alloca_dtype%array_j
+
+end program main
+
+!CHECK: 1 2 3 4 5 6 7 8 9 10
diff --git a/offload/test/offloading/fortran/target-map-alloca-dtype-and-alloca-array-v2.f90 b/offload/test/offloading/fortran/target-map-alloca-dtype-and-alloca-array-v2.f90
new file mode 100644
index 00000000000000..54a32160c7a61d
--- /dev/null
+++ b/offload/test/offloading/fortran/target-map-alloca-dtype-and-alloca-array-v2.f90
@@ -0,0 +1,34 @@
+! Offload test that checks an allocatable derived type can be mapped alongside
+! one of its own allocatable components without disrupting either mapping,
+! different from original as the argument ordering is reversed (similar to C++
+! mapping of a struct and a pointer, in concept at least).
+! REQUIRES: flang, amdgpu
+
+! RUN: %libomptarget-compile-fortran-run-and-check-generic
+program main
+ type :: dtype
+ real(4) :: i
+ integer, allocatable :: scalar
+ integer(4) :: array_i(10)
+ real(4) :: j
+ integer, allocatable :: array_j(:)
+ integer(4) :: k
+ end type dtype
+
+ type(dtype), allocatable :: alloca_dtype
+ allocate(alloca_dtype)
+ allocate(alloca_dtype%array_j(10))
+
+!$omp target map(tofrom: alloca_dtype%array_j, alloca_dtype)
+ do i = 1, 10
+ alloca_dtype%array_j(i) = i
+ end do
+ alloca_dtype%k = 50
+!$omp end target
+
+print *, alloca_dtype%array_j
+print *, alloca_dtype%k
+end program main
+
+!CHECK: 1 2 3 4 5 6 7 8 9 10
+!CHECK: 50
diff --git a/offload/test/offloading/fortran/target-map-alloca-dtype-and-alloca-array.f90 b/offload/test/offloading/fortran/target-map-alloca-dtype-and-alloca-array.f90
new file mode 100644
index 00000000000000..2b1957a8451c13
--- /dev/null
+++ b/offload/test/offloading/fortran/target-map-alloca-dtype-and-alloca-array.f90
@@ -0,0 +1,33 @@
+! Offload test that checks an allocatable derived type can be mapped alongside
+! one of its own allocatable components without disrupting either mapping
+! (similar to C++ mapping of a struct and a pointer, in concept at least).
+! REQUIRES: flang, amdgpu
+
+! RUN: %libomptarget-compile-fortran-run-and-check-generic
+program main
+ type :: dtype
+ real(4) :: i
+ integer, allocatable :: scalar
+ integer(4) :: array_i(10)
+ real(4) :: j
+ integer, allocatable :: array_j(:)
+ integer(4) :: k
+ end type dtype
+
+ type(dtype), allocatable :: alloca_dtype
+ allocate(alloca_dtype)
+ allocate(alloca_dtype%array_j(10))
+
+!$omp target map(tofrom: alloca_dtype, alloca_dtype%array_j)
+ do i = 1, 10
+ alloca_dtype%array_j(i) = i
+ end do
+ alloca_dtype%k = 50
+!$omp end target
+
+print *, alloca_dtype%array_j
+print *, alloca_dtype%k
+end program main
+
+!CHECK: 1 2 3 4 5 6 7 8 9 10
+!CHECK: 50
diff --git a/offload/test/offloading/fortran/target-map-alloca-dtype-array-and-scalar.f90 b/offload/test/offloading/fortran/target-map-alloca-dtype-array-and-scalar.f90
new file mode 100644
index 00000000000000..30f35be98af605
--- /dev/null
+++ b/offload/test/offloading/fortran/target-map-alloca-dtype-array-and-scalar.f90
@@ -0,0 +1,39 @@
+! Offloading test checking interaction of explicit member mapping of
+! non-allocatable members of an allocatable derived type.
+! REQUIRES: flang, amdgpu
+
+! RUN: %libomptarget-compile-fortran-run-and-check-generic
+program main
+ type :: nested_dtype
+ real(4) :: i
+ real(4) :: j
+ integer(4) :: array_i(10)
+ integer(4) :: k
+ end type nested_dtype
+
+ type :: dtype
+ real(4) :: i
+ integer, allocatable :: scalar
+ integer(4) :: array_i(10)
+ type(nested_dtype) :: nested_dtype
+ real(4) :: j
+ integer, allocatable :: array_j(:)
+ integer(4) :: k
+ end type dtype
+
+ type(dtype), allocatable :: alloca_dtype
+ allocate(alloca_dtype)
+
+!$omp target map(tofrom: alloca_dtype%nested_dtype%array_i, alloca_dtype%k)
+ do i = 1, 10
+ alloca_dtype%nested_dtype%array_i(i) = i
+ end do
+ alloca_dtype%k = 50
+!$omp end target
+
+print *, alloca_dtype%k
+print *, alloca_dtype%nested_dtype%array_i
+end program main
+
+!CHECK: 50
+!CHECK: 1 2 3 4 5 6 7 8 9 10
diff --git a/offload/test/offloading/fortran/target-map-alloca-dtype-array-of-dtype.f90 b/offload/test/offloading/fortran/target-map-alloca-dtype-array-of-dtype.f90
new file mode 100644
index 00000000000000..bad8ff55e638ba
--- /dev/null
+++ b/offload/test/offloading/fortran/target-map-alloca-dtype-array-of-dtype.f90
@@ -0,0 +1,35 @@
+! Offloading test checking interaction of explicit member mapping of an array
+! of derived types contained within an allocatable derived type
+! REQUIRES: flang, amdgpu
+
+! RUN: %libomptarget-compile-fortran-run-and-check-generic
+program main
+ type :: nested_dtype
+ real(4) :: i
+ real(4) :: j
+ integer(4) :: array_i(10)
+ integer(4) :: k
+ end type nested_dtype
+
+ type :: dtype
+ real(4) :: i
+ integer(4) :: array_i(10)
+ real(4) :: j
+ type(nested_dtype) :: array_dtype(10)
+ integer(4) :: k
+ end type dtype
+
+ type(dtype), allocatable :: dtyped
+ allocate(dtyped)
+
+!$omp target map(tofrom: dtyped%array_dtype)
+ do i = 1, 10
+ dtyped%array_dtype(i)%k = i
+ end do
+!$omp end target
+
+print *, dtyped%array_dtype%k
+
+end program main
+
+!CHECK: 1 2 3 4 5 6 7 8 9 10
diff --git a/offload/test/offloading/fortran/target-map-allocatable-array-section-1d-bounds.f90 b/offload/test/offloading/fortran/target-map-allocatable-array-section-1d-bounds.f90
index 3e981116ab42f1..7734ca9d0cf0d4 100644
--- a/offload/test/offloading/fortran/target-map-allocatable-array-section-1d-bounds.f90
+++ b/offload/test/offloading/fortran/target-map-allocatable-array-section-1d-bounds.f90
@@ -1,6 +1,5 @@
-! Offloading test checking interaction of a
-! two 1-D allocatable arrays with a target region
-! while providing the map upper and lower bounds
+! Offloading test checking interaction of a two 1-D allocatable arrays with a
+! target region while providing the map upper and lower bounds
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/target-map-allocatable-array-section-3d-bounds.f90 b/offload/test/offloading/fortran/target-map-allocatable-array-section-3d-bounds.f90
index 31b6daa35ca5e8..7dba860a4a8328 100644
--- a/offload/test/offloading/fortran/target-map-allocatable-array-section-3d-bounds.f90
+++ b/offload/test/offloading/fortran/target-map-allocatable-array-section-3d-bounds.f90
@@ -1,6 +1,5 @@
-! Offloading test checking interaction of allocatables
-! with multi-dimensional bounds (3-D in this case) and
-! a target region
+! Offloading test checking interaction of allocatables with multi-dimensional
+! bounds (3-D in this case) and a target region
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/target-map-allocatable-dtype.f90 b/offload/test/offloading/fortran/target-map-allocatable-dtype.f90
new file mode 100644
index 00000000000000..13b8890eee9a87
--- /dev/null
+++ b/offload/test/offloading/fortran/target-map-allocatable-dtype.f90
@@ -0,0 +1,31 @@
+! Offload test that checks an allocatable derived type can be mapped and at the
+! least non-allocatable components can be accessed.
+! REQUIRES: flang, amdgpu
+
+! RUN: %libomptarget-compile-fortran-run-and-check-generic
+program main
+ type :: dtype
+ real(4) :: i
+ integer, allocatable :: scalar
+ integer(4) :: array_i(10)
+ real(4) :: j
+ integer, allocatable :: array_j(:)
+ integer(4) :: k
+ end type dtype
+
+ type(dtype), allocatable :: alloca_dtype
+ allocate(alloca_dtype)
+
+!$omp target map(tofrom: alloca_dtype)
+ do i = 1, 10
+ alloca_dtype%array_i(i) = i
+ end do
+ alloca_dtype%k = 50
+!$omp end target
+
+print *, alloca_dtype%k
+print *, alloca_dtype%array_i
+end program main
+
+!CHECK: 50
+!CHECK: 1 2 3 4 5 6 7 8 9 10
diff --git a/offload/test/offloading/fortran/target-map-allocatable-map-scopes.f90 b/offload/test/offloading/fortran/target-map-allocatable-map-scopes.f90
index 4a97a9ade91cdc..fe9c70900fefac 100644
--- a/offload/test/offloading/fortran/target-map-allocatable-map-scopes.f90
+++ b/offload/test/offloading/fortran/target-map-allocatable-map-scopes.f90
@@ -1,5 +1,5 @@
-! Offloading test checking interaction of allocatables
-! with target in different scopes
+! Offloading test checking interaction of allocatables with target in different
+! scopes
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/target-map-common-block.f90 b/offload/test/offloading/fortran/target-map-common-block.f90
index d2705db5d6fffb..f368762b46d49d 100644
--- a/offload/test/offloading/fortran/target-map-common-block.f90
+++ b/offload/test/offloading/fortran/target-map-common-block.f90
@@ -1,6 +1,5 @@
-! Offloading test checking interaction of
-! mapping a full common block in a target
-! region
+! Offloading test checking interaction of mapping a full common block in a
+! target region
! REQUIRES: flang, amdgcn-amd-amdhsa
! UNSUPPORTED: nvptx64-nvidia-cuda
! UNSUPPORTED: nvptx64-nvidia-cuda-LTO
diff --git a/offload/test/offloading/fortran/target-map-declare-target-link-common-block.f90 b/offload/test/offloading/fortran/target-map-declare-target-link-common-block.f90
index 857e79c5fa6e21..697365709d2197 100644
--- a/offload/test/offloading/fortran/target-map-declare-target-link-common-block.f90
+++ b/offload/test/offloading/fortran/target-map-declare-target-link-common-block.f90
@@ -1,7 +1,5 @@
-! Offloading test checking interaction of
-! mapping a declare target link common
-! block with device_type any to a target
-! region
+! Offloading test checking interaction of mapping a declare target link common
+! block with device_type any to a target region
! REQUIRES: flang, amdgcn-amd-amdhsa
! UNSUPPORTED: nvptx64-nvidia-cuda
! UNSUPPORTED: nvptx64-nvidia-cuda-LTO
diff --git a/offload/test/offloading/fortran/target-map-derived-type-full-1.f90 b/offload/test/offloading/fortran/target-map-derived-type-full-1.f90
index fe3b84398eaf01..9f2aeb4bf9fc07 100644
--- a/offload/test/offloading/fortran/target-map-derived-type-full-1.f90
+++ b/offload/test/offloading/fortran/target-map-derived-type-full-1.f90
@@ -1,7 +1,5 @@
-! Offloading test checking interaction of an
-! explicit derived type mapping when mapped
-! to target and assinging one derived type
-! to another
+! Offloading test checking interaction of an explicit derived type mapping when
+! mapped to target and assinging one derived type to another
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/target-map-derived-type-full-2.f90 b/offload/test/offloading/fortran/target-map-derived-type-full-2.f90
index 302af23a3c7e8b..f4f63f233cc046 100644
--- a/offload/test/offloading/fortran/target-map-derived-type-full-2.f90
+++ b/offload/test/offloading/fortran/target-map-derived-type-full-2.f90
@@ -1,6 +1,5 @@
-! Offloading test checking interaction of an
-! explicit derived type mapping when mapped to
-! target and assigning to individual members
+! Offloading test checking interaction of an explicit derived type mapping when
+! mapped to target and assigning to individual members
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/target-map-derived-type-full-implicit-1.f90 b/offload/test/offloading/fortran/target-map-derived-type-full-implicit-1.f90
index f43fa3cc69055f..8632b951d6fbd6 100644
--- a/offload/test/offloading/fortran/target-map-derived-type-full-implicit-1.f90
+++ b/offload/test/offloading/fortran/target-map-derived-type-full-implicit-1.f90
@@ -1,7 +1,5 @@
-! Offloading test checking interaction of an
-! implicit derived type mapping when mapped
-! to target and assinging one derived type
-! to another
+! Offloading test checking interaction of an implicit derived type mapping when
+! mapped to target and assinging one derived type to another
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/target-map-derived-type-full-implicit-2.f90 b/offload/test/offloading/fortran/target-map-derived-type-full-implicit-2.f90
index f6c8f9812b14c0..9331a48c3eb75e 100644
--- a/offload/test/offloading/fortran/target-map-derived-type-full-implicit-2.f90
+++ b/offload/test/offloading/fortran/target-map-derived-type-full-implicit-2.f90
@@ -1,7 +1,5 @@
-! Offloading test checking interaction of an
-! explicit derived type mapping when mapped
-! to target and assinging one derived type
-! to another
+! Offloading test checking interaction of an explicit derived type mapping when
+! mapped to target and assinging one derived type to another
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/target-map-double-large-nested-dtype-multi-member.f90 b/offload/test/offloading/fortran/target-map-double-large-nested-dtype-multi-member.f90
index e390481bbaba0a..ef27ad387ea88b 100644
--- a/offload/test/offloading/fortran/target-map-double-large-nested-dtype-multi-member.f90
+++ b/offload/test/offloading/fortran/target-map-double-large-nested-dtype-multi-member.f90
@@ -1,6 +1,5 @@
-! Offloading test checking interaction of an
-! explicit member map from two large nested
-! derived types
+! Offloading test checking interaction of an explicit member map from two large
+! nested derived types
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/target-map-double-nested-dtype-array-bounds.f90 b/offload/test/offloading/fortran/target-map-double-nested-dtype-array-bounds.f90
index 7f260ac4cdc1ed..b90fbd05fb2e83 100644
--- a/offload/test/offloading/fortran/target-map-double-nested-dtype-array-bounds.f90
+++ b/offload/test/offloading/fortran/target-map-double-nested-dtype-array-bounds.f90
@@ -1,6 +1,5 @@
-! Offloading test checking interaction of two
-! explicit arrau member maps with bounds from
-! two nested derived types
+! Offloading test checking interaction of two explicit array member maps with
+! bounds from two nested derived types
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/target-map-double-nested-dtype-double-array-bounds.f90 b/offload/test/offloading/fortran/target-map-double-nested-dtype-double-array-bounds.f90
index bd9bbb1b7eed50..f637dbed470c2f 100644
--- a/offload/test/offloading/fortran/target-map-double-nested-dtype-double-array-bounds.f90
+++ b/offload/test/offloading/fortran/target-map-double-nested-dtype-double-array-bounds.f90
@@ -1,6 +1,5 @@
-! Offloading test checking interaction of two
-! explicit array member maps with array bounds
-! from two nested derived types
+! Offloading test checking interaction of two explicit array member maps with
+! array bounds from two nested derived types
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/target-map-double-nested-dtype-single-member.f90 b/offload/test/offloading/fortran/target-map-double-nested-dtype-single-member.f90
index 3c3b5e4b91e2fd..cbf1c6877bdefa 100644
--- a/offload/test/offloading/fortran/target-map-double-nested-dtype-single-member.f90
+++ b/offload/test/offloading/fortran/target-map-double-nested-dtype-single-member.f90
@@ -1,6 +1,5 @@
-! Offloading test checking interaction of an
-! explicit derived type member mapping of two
-! derived types for a single array member each
+! Offloading test checking interaction of an explicit derived type member
+! mapping of two derived types for a single array member each
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/target-map-dtype-3d-alloca-array-with-bounds.f90 b/offload/test/offloading/fortran/target-map-dtype-3d-alloca-array-with-bounds.f90
new file mode 100644
index 00000000000000..9fa13339aaddb1
--- /dev/null
+++ b/offload/test/offloading/fortran/target-map-dtype-3d-alloca-array-with-bounds.f90
@@ -0,0 +1,41 @@
+! Offload test that checks an allocatable array can be mapped with a specified
+! 3-D bounds when contained within a derived type and mapped via member mapping.
+! REQUIRES: flang, amdgpu
+
+! RUN: %libomptarget-compile-fortran-run-and-check-generic
+program main
+ type :: top_layer
+ real(4) :: i
+ integer, allocatable :: scalar
+ integer(4) :: array_i(10)
+ real(4) :: j
+ integer, allocatable :: array_j(:,:,:)
+ integer(4) :: k
+ end type top_layer
+
+ type(top_layer) :: one_l
+ integer :: inArray(3,3,3)
+
+ allocate(one_l%array_j(3,3,3))
+
+ do i = 1, 3
+ do j = 1, 3
+ do k = 1, 3
+ inArray(i, j, k) = 42
+ one_l%array_j(i, j, k) = 0
+ end do
+ end do
+ end do
+
+!$omp target map(tofrom: one_l%array_j(1:3, 1:3, 2:2)) map(to: inArray(1:3, 1:3, 1:3))
+ do j = 1, 3
+ do k = 1, 3
+ one_l%array_j(k, j, 2) = inArray(k, j, 2)
+ end do
+ end do
+!$omp end target
+
+ print *, one_l%array_j
+end program main
+
+!CHECK: 0 0 0 0 0 0 0 0 0 42 42 42 42 42 42 42 42 42 0 0 0 0 0 0 0 0 0
diff --git a/offload/test/offloading/fortran/target-map-dtype-alloca-and-non-alloca-array.f90 b/offload/test/offloading/fortran/target-map-dtype-alloca-and-non-alloca-array.f90
new file mode 100644
index 00000000000000..c72f82a806732a
--- /dev/null
+++ b/offload/test/offloading/fortran/target-map-dtype-alloca-and-non-alloca-array.f90
@@ -0,0 +1,36 @@
+! Offload test that checks an allocatable array can be mapped alongside a
+! non-allocatable array when both are contained within a derived type can be
+! mapped correctly via member mapping and then written to.
+! REQUIRES: flang, amdgpu
+
+! RUN: %libomptarget-compile-fortran-run-and-check-generic
+program main
+ type :: one_layer
+ real(4) :: i
+ integer, allocatable :: scalar
+ integer(4) :: array_i(10)
+ real(4) :: j
+ integer, allocatable :: array_j(:)
+ integer(4) :: k
+ end type one_layer
+
+ type(one_layer) :: one_l
+
+ allocate(one_l%array_j(10))
+
+ do i = 1, 10
+ one_l%array_i(i) = i
+ end do
+
+!$omp target map(tofrom: one_l%array_i, one_l%array_j)
+ do i = 1, 10
+ one_l%array_j(i) = one_l%array_i(i) + i
+ end do
+!$omp end target
+
+ print *, one_l%array_i
+ print *, one_l%array_j
+end program main
+
+!CHECK: 1 2 3 4 5 6 7 8 9 10
+!CHECK: 2 4 6 8 10 12 14 16 18 20
diff --git a/offload/test/offloading/fortran/target-map-dtype-alloca-array-and-non-alloca-dtype.f90 b/offload/test/offloading/fortran/target-map-dtype-alloca-array-and-non-alloca-dtype.f90
new file mode 100644
index 00000000000000..172b3c4683f8b9
--- /dev/null
+++ b/offload/test/offloading/fortran/target-map-dtype-alloca-array-and-non-alloca-dtype.f90
@@ -0,0 +1,44 @@
+! Offload test that checks an allocatable array can be mapped alongside a
+! non-allocatable derived type when both are contained within a derived type
+! can be mapped correctly via member mapping and then written to.
+! REQUIRES: flang, amdgpu
+
+! RUN: %libomptarget-compile-fortran-run-and-check-generic
+program main
+ type :: bottom_layer
+ real(4) :: i
+ integer(4) :: array_i(10)
+ integer(4) :: k
+ end type bottom_layer
+
+ type :: top_layer
+ real(4) :: i
+ integer, allocatable :: scalar
+ integer(4) :: array_i(10)
+ real(4) :: j
+ integer, allocatable :: array_j(:)
+ integer(4) :: k
+ type(bottom_layer) :: nest
+ end type top_layer
+
+ type(top_layer) :: one_l
+
+ allocate(one_l%array_j(10))
+ allocate(one_l%scalar)
+
+ do i = 1, 10
+ one_l%nest%array_i(i) = i
+ end do
+
+!$omp target map(tofrom: one_l%nest, one_l%array_j)
+ do i = 1, 10
+ one_l%array_j(i) = one_l%nest%array_i(i) + i
+ end do
+!$omp end target
+
+ print *, one_l%nest%array_i
+ print *, one_l%array_j
+end program main
+
+!CHECK: 1 2 3 4 5 6 7 8 9 10
+!CHECK: 2 4 6 8 10 12 14 16 18 20
diff --git a/offload/test/offloading/fortran/target-map-dtype-alloca-array-of-dtype.f90 b/offload/test/offloading/fortran/target-map-dtype-alloca-array-of-dtype.f90
new file mode 100644
index 00000000000000..f56a72843e6dfc
--- /dev/null
+++ b/offload/test/offloading/fortran/target-map-dtype-alloca-array-of-dtype.f90
@@ -0,0 +1,34 @@
+! Offload test that checks it is possible to member map an allocatable array of
+! derived types nested within a non-allocatable derived type.
+! REQUIRES: flang, amdgpu
+
+! RUN: %libomptarget-compile-fortran-run-and-check-generic
+program main
+ type :: nested_dtype
+ real(4) :: i
+ real(4) :: j
+ integer(4) :: array_i(10)
+ integer(4) :: k
+ end type nested_dtype
+
+ type :: dtype
+ real(4) :: i
+ integer(4) :: array_i(10)
+ real(4) :: j
+ type(nested_dtype), allocatable :: array_dtype(:)
+ integer(4) :: k
+ end type dtype
+
+ type(dtype) :: dtyped
+ allocate(dtyped%array_dtype(10))
+
+!$omp target map(tofrom: dtyped%array_dtype)
+ do i = 1, 10
+ dtyped%array_dtype(i)%k = i
+ end do
+!$omp end target
+
+print *, dtyped%array_dtype%k
+end program main
+
+!CHECK: 1 2 3 4 5 6 7 8 9 10
diff --git a/offload/test/offloading/fortran/target-map-dtype-alloca-array-with-bounds.f90 b/offload/test/offloading/fortran/target-map-dtype-alloca-array-with-bounds.f90
new file mode 100644
index 00000000000000..53480d1d569993
--- /dev/null
+++ b/offload/test/offloading/fortran/target-map-dtype-alloca-array-with-bounds.f90
@@ -0,0 +1,29 @@
+! Offload test that checks an allocatable array can be mapped with a specified
+! 1-D bounds when contained within a derived type and mapped via member mapping
+! REQUIRES: flang, amdgpu
+
+! RUN: %libomptarget-compile-fortran-run-and-check-generic
+program main
+ type :: top_layer
+ real(4) :: i
+ integer, allocatable :: scalar
+ integer(4) :: array_i(10)
+ real(4) :: j
+ integer, allocatable :: array_j(:)
+ integer(4) :: k
+ end type top_layer
+
+ type(top_layer) :: one_l
+
+ allocate(one_l%array_j(10))
+
+!$omp target map(tofrom: one_l%array_j(2:6))
+ do index = 1, 10
+ one_l%array_j(index) = index
+ end do
+!$omp end target
+
+ print *, one_l%array_j(2:6)
+end program main
+
+!CHECK: 2 3 4 5 6
diff --git a/offload/test/offloading/fortran/target-map-dtype-allocatable-array.f90 b/offload/test/offloading/fortran/target-map-dtype-allocatable-array.f90
new file mode 100644
index 00000000000000..dbd839637f280d
--- /dev/null
+++ b/offload/test/offloading/fortran/target-map-dtype-allocatable-array.f90
@@ -0,0 +1,28 @@
+! Offload test that checks an allocatable array contained within a derived type
+! can be mapped correctly via member mapping and then written to.
+! REQUIRES: flang, amdgpu
+
+! RUN: %libomptarget-compile-fortran-run-and-check-generic
+program main
+ type :: one_layer
+ real(4) :: i
+ integer, allocatable :: scalar
+ integer(4) :: array_i(10)
+ real(4) :: j
+ integer, allocatable :: array_j(:)
+ integer(4) :: k
+ end type one_layer
+
+ type(one_layer) :: one_l
+ allocate(one_l%array_j(10))
+
+ !$omp target map(tofrom: one_l%array_j)
+ do i = 1, 10
+ one_l%array_j(i) = i
+ end do
+ !$omp end target
+
+ print *, one_l%array_j
+end program main
+
+!CHECK: 1 2 3 4 5 6 7 8 9 10
diff --git a/offload/test/offloading/fortran/target-map-dtype-allocatable-scalar-and-array.f90 b/offload/test/offloading/fortran/target-map-dtype-allocatable-scalar-and-array.f90
new file mode 100644
index 00000000000000..352d02e34caccf
--- /dev/null
+++ b/offload/test/offloading/fortran/target-map-dtype-allocatable-scalar-and-array.f90
@@ -0,0 +1,34 @@
+! Offload test that checks an allocatable array alongside an allocatable scalar
+! contained within a derived type can be mapped correctly via member mapping
+! and then written to.
+! REQUIRES: flang, amdgpu
+
+! RUN: %libomptarget-compile-fortran-run-and-check-generic
+program main
+ type :: one_layer
+ real(4) :: i
+ integer, allocatable :: scalar
+ integer(4) :: array_i(10)
+ real(4) :: j
+ integer, allocatable :: array_j(:)
+ integer(4) :: k
+ end type one_layer
+
+ type(one_layer) :: one_l
+
+ allocate(one_l%array_j(10))
+ allocate(one_l%scalar)
+
+ !$omp target map(tofrom: one_l%array_j, one_l%j)
+ do i = 1, 10
+ one_l%array_j(i) = i
+ end do
+ one_l%j = 50
+ !$omp end target
+
+ print *, one_l%j
+ print *, one_l%array_j
+end program main
+
+!CHECK: 50
+!CHECK: 1 2 3 4 5 6 7 8 9 10
diff --git a/offload/test/offloading/fortran/target-map-dtype-arr-bounds-member-enter-exit-update.f90 b/offload/test/offloading/fortran/target-map-dtype-arr-bounds-member-enter-exit-update.f90
index e3c28062687c84..74bbdc0a681099 100644
--- a/offload/test/offloading/fortran/target-map-dtype-arr-bounds-member-enter-exit-update.f90
+++ b/offload/test/offloading/fortran/target-map-dtype-arr-bounds-member-enter-exit-update.f90
@@ -1,8 +1,6 @@
-! Offloading test checking interaction of an
-! explicit derived type member mapping of
-! an array with bounds when mapped to
-! target using a combination of update,
-! enter and exit directives.
+! Offloading test checking interaction of an explicit derived type member
+! mapping of an array with bounds when mapped to target using a combination of
+! update, enter and exit directives.
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/target-map-dtype-arr-bounds-member-enter-exit.f90 b/offload/test/offloading/fortran/target-map-dtype-arr-bounds-member-enter-exit.f90
index fd56142c5cbf25..8dcd7b5f39f3ac 100644
--- a/offload/test/offloading/fortran/target-map-dtype-arr-bounds-member-enter-exit.f90
+++ b/offload/test/offloading/fortran/target-map-dtype-arr-bounds-member-enter-exit.f90
@@ -1,8 +1,6 @@
-! Offloading test checking interaction of an
-! explicit derived type member mapping of
-! an array with bounds when mapped to
-! target using a combination of enter and
-! exit directives.
+! Offloading test checking interaction of an explicit derived type member
+! mapping of an array with bounds when mapped to target using a combination of
+! enter and exit directives.
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/target-map-dtype-explicit-individual-array-member.f90 b/offload/test/offloading/fortran/target-map-dtype-explicit-individual-array-member.f90
index ce8a1b2ba84bae..c4496a3e411a65 100644
--- a/offload/test/offloading/fortran/target-map-dtype-explicit-individual-array-member.f90
+++ b/offload/test/offloading/fortran/target-map-dtype-explicit-individual-array-member.f90
@@ -1,6 +1,5 @@
-! Offloading test checking interaction of an
-! explicit derived type member mapping of
-! an array when mapped to target
+! Offloading test checking interaction of an explicit derived type member
+! mapping of an array when mapped to target
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/target-map-dtype-multi-explicit-array-3D-member-bounds.f90 b/offload/test/offloading/fortran/target-map-dtype-multi-explicit-array-3D-member-bounds.f90
index c72bb853780952..145818fd4111a4 100644
--- a/offload/test/offloading/fortran/target-map-dtype-multi-explicit-array-3D-member-bounds.f90
+++ b/offload/test/offloading/fortran/target-map-dtype-multi-explicit-array-3D-member-bounds.f90
@@ -1,7 +1,5 @@
-! Offloading test checking interaction of an
-! explicit derived type member mapping of
-! two arrays with explicit bounds when
-! mapped to target
+! Offloading test checking interaction of an explicit derived type member
+! mapping of two arrays with explicit bounds when mapped to target
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/target-map-dtype-multi-explicit-array-member-bounds.f90 b/offload/test/offloading/fortran/target-map-dtype-multi-explicit-array-member-bounds.f90
index b8defce2abc726..1a4742461f8c27 100644
--- a/offload/test/offloading/fortran/target-map-dtype-multi-explicit-array-member-bounds.f90
+++ b/offload/test/offloading/fortran/target-map-dtype-multi-explicit-array-member-bounds.f90
@@ -1,7 +1,5 @@
-! Offloading test checking interaction of an
-! explicit derived type member mapping of
-! two arrays with explicit bounds when
-! mapped to target
+! Offloading test checking interaction of an explicit derived type member
+! mapping of two arrays with explicit bounds when mapped to target
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/target-map-dtype-multi-explicit-array-member.f90 b/offload/test/offloading/fortran/target-map-dtype-multi-explicit-array-member.f90
index 5816598b5b50d5..d05b2dafebb1b2 100644
--- a/offload/test/offloading/fortran/target-map-dtype-multi-explicit-array-member.f90
+++ b/offload/test/offloading/fortran/target-map-dtype-multi-explicit-array-member.f90
@@ -1,6 +1,5 @@
-! Offloading test checking interaction of an
-! derived type mapping of two explicit array
-! members to target
+! Offloading test checking interaction of an derived type mapping of two
+! explicit array members to target
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/target-map-dtype-multi-explicit-member.f90 b/offload/test/offloading/fortran/target-map-dtype-multi-explicit-member.f90
index e869804470165b..1bda6d67f2b271 100644
--- a/offload/test/offloading/fortran/target-map-dtype-multi-explicit-member.f90
+++ b/offload/test/offloading/fortran/target-map-dtype-multi-explicit-member.f90
@@ -1,6 +1,5 @@
-! Offloading test checking interaction of an
-! derived type mapping of two explicit
-! members to target
+! Offloading test checking interaction of an derived type mapping of two
+! explicit members to target
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/target-map-enter-exit-allocatables.f90 b/offload/test/offloading/fortran/target-map-enter-exit-allocatables.f90
index 60806feb7a1912..497b824b4fc72e 100644
--- a/offload/test/offloading/fortran/target-map-enter-exit-allocatables.f90
+++ b/offload/test/offloading/fortran/target-map-enter-exit-allocatables.f90
@@ -1,5 +1,5 @@
-! Offloading test checking interaction of allocatables
-! with enter, exit and target
+! Offloading test checking interaction of allocatables with enter, exit and
+! target
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/target-map-enter-exit-array-2.f90 b/offload/test/offloading/fortran/target-map-enter-exit-array-2.f90
index 320b76fcdb467f..b6005e037e8365 100644
--- a/offload/test/offloading/fortran/target-map-enter-exit-array-2.f90
+++ b/offload/test/offloading/fortran/target-map-enter-exit-array-2.f90
@@ -1,5 +1,5 @@
-! Offloading test checking interaction of an
-! enter and exit map of an array of scalars
+! Offloading test checking interaction of an enter and exit map of an array of
+! scalars
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/target-map-enter-exit-array-bounds.f90 b/offload/test/offloading/fortran/target-map-enter-exit-array-bounds.f90
index cae1d47013f622..d6264c60ba30ed 100644
--- a/offload/test/offloading/fortran/target-map-enter-exit-array-bounds.f90
+++ b/offload/test/offloading/fortran/target-map-enter-exit-array-bounds.f90
@@ -1,6 +1,5 @@
-! Offloading test checking interaction of an
-! enter and exit map of an array of scalars
-! with specified bounds
+! Offloading test checking interaction of an enter and exit map of an array of
+! scalars with specified bounds
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/target-map-enter-exit-array.f90 b/offload/test/offloading/fortran/target-map-enter-exit-array.f90
index 67946ba66cd961..51de70f092ef6b 100644
--- a/offload/test/offloading/fortran/target-map-enter-exit-array.f90
+++ b/offload/test/offloading/fortran/target-map-enter-exit-array.f90
@@ -1,5 +1,5 @@
-! Offloading test checking interaction of fixed size
-! arrays with enter, exit and target
+! Offloading test checking interaction of fixed size arrays with enter, exit
+! and target
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/target-map-enter-exit-scalar.f90 b/offload/test/offloading/fortran/target-map-enter-exit-scalar.f90
index 046a906dd524dd..7e252259007fe8 100644
--- a/offload/test/offloading/fortran/target-map-enter-exit-scalar.f90
+++ b/offload/test/offloading/fortran/target-map-enter-exit-scalar.f90
@@ -1,5 +1,4 @@
-! Offloading test checking interaction of an
-! enter and exit map of an scalar
+! Offloading test checking interaction of an enter and exit map of an scalar
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/target-map-first-common-block-member.f90 b/offload/test/offloading/fortran/target-map-first-common-block-member.f90
index 57a7380221ad81..4f72f30cd51d7f 100644
--- a/offload/test/offloading/fortran/target-map-first-common-block-member.f90
+++ b/offload/test/offloading/fortran/target-map-first-common-block-member.f90
@@ -1,6 +1,5 @@
-! Offloading test checking interaction of
-! mapping a member of a common block to a
-! target region
+! Offloading test checking interaction of mapping a member of a common block to
+! a target region
! REQUIRES: flang, amdgcn-amd-amdhsa
! UNSUPPORTED: nvptx64-nvidia-cuda
! UNSUPPORTED: nvptx64-nvidia-cuda-LTO
diff --git a/offload/test/offloading/fortran/target-map-individual-dtype-member-map.f90 b/offload/test/offloading/fortran/target-map-individual-dtype-member-map.f90
index 42a09499691058..081718e0448cde 100644
--- a/offload/test/offloading/fortran/target-map-individual-dtype-member-map.f90
+++ b/offload/test/offloading/fortran/target-map-individual-dtype-member-map.f90
@@ -1,6 +1,5 @@
-! Offloading test checking interaction of an
-! single explicit member map from a single
-! derived type.
+! Offloading test checking interaction of an single explicit member map from a
+! single derived type.
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/target-map-large-nested-dtype-multi-member.f90 b/offload/test/offloading/fortran/target-map-large-nested-dtype-multi-member.f90
index 2e345fd49cfaa5..0b9fcea4422f4a 100644
--- a/offload/test/offloading/fortran/target-map-large-nested-dtype-multi-member.f90
+++ b/offload/test/offloading/fortran/target-map-large-nested-dtype-multi-member.f90
@@ -1,6 +1,5 @@
-! Offloading test checking interaction of an
-! explicit member map a large nested derived
-! type
+! Offloading test checking interaction of an explicit member map a large nested
+! derived type
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/target-map-mix-imp-exp-common-block-members.f90 b/offload/test/offloading/fortran/target-map-mix-imp-exp-common-block-members.f90
index a634cd023c57c1..8c2907a87721db 100644
--- a/offload/test/offloading/fortran/target-map-mix-imp-exp-common-block-members.f90
+++ b/offload/test/offloading/fortran/target-map-mix-imp-exp-common-block-members.f90
@@ -1,7 +1,5 @@
-! Offloading test checking interaction of
-! mapping all the members of a common block
-! with a mix of explicit and implicit
-! mapping to a target region
+! Offloading test checking interaction of mapping all the members of a common
+! block with a mix of explicit and implicit mapping to a target region
! REQUIRES: flang, amdgcn-amd-amdhsa
! UNSUPPORTED: nvptx64-nvidia-cuda
! UNSUPPORTED: nvptx64-nvidia-cuda-LTO
diff --git a/offload/test/offloading/fortran/target-map-multi-alloca-dtypes-with-multi-alloca-members.f90 b/offload/test/offloading/fortran/target-map-multi-alloca-dtypes-with-multi-alloca-members.f90
new file mode 100644
index 00000000000000..7880069881acc1
--- /dev/null
+++ b/offload/test/offloading/fortran/target-map-multi-alloca-dtypes-with-multi-alloca-members.f90
@@ -0,0 +1,90 @@
+! Offloading test checking interaction of an explicit member map allocatable
+! components of two large nested derived types. NOTE: Unfortunately this test
+! loses a bit of its bite as we do not currently support linking against an
+! offload compiled fortran runtime library which means allocatable scalar
+! assignment isn't going to work in target regions.
+! REQUIRES: flang, amdgpu
+
+! RUN: %libomptarget-compile-fortran-run-and-check-generic
+program main
+ type :: bottom_layer1
+ real(4), allocatable :: i4
+ real(4), allocatable :: j4
+ integer, pointer :: array_ptr(:)
+ real(4), allocatable :: k4
+ end type bottom_layer1
+
+ type :: bottom_layer2
+ integer(4), allocatable :: i3
+ integer(4), allocatable :: j3
+ integer, allocatable :: scalar
+ real, allocatable :: array_j(:)
+ integer(4), allocatable :: k3
+ end type bottom_layer2
+
+ type :: middle_layer
+ real(4) :: array_i2(10)
+ real(4), allocatable :: i2
+ integer, pointer :: scalar_ptr
+ real(4) :: array_j2(10)
+ type(bottom_layer1), allocatable :: nest
+ type(bottom_layer2), allocatable :: nest2
+ end type middle_layer
+
+ type :: top_layer
+ real(4) :: i
+ integer(4), allocatable :: array_i(:)
+ real(4) :: j
+ integer(4) :: k
+ type(middle_layer), allocatable :: nested
+ end type top_layer
+
+ type(top_layer), allocatable :: top_dtype
+ type(top_layer), allocatable :: top_dtype2
+ integer, target :: array_target(10)
+ integer, target :: array_target2(10)
+
+ allocate(top_dtype)
+ allocate(top_dtype2)
+ allocate(top_dtype%nested)
+ allocate(top_dtype2%nested)
+ allocate(top_dtype%nested%nest)
+ allocate(top_dtype2%nested%nest)
+ allocate(top_dtype%nested%nest2)
+ allocate(top_dtype2%nested%nest2)
+ allocate(top_dtype%array_i(10))
+ allocate(top_dtype2%array_i(10))
+
+ top_dtype%nested%nest%array_ptr => array_target
+ allocate(top_dtype%nested%nest2%array_j(10))
+
+ top_dtype2%nested%nest%array_ptr => array_target2
+ allocate(top_dtype2%nested%nest2%array_j(10))
+
+!$omp target map(tofrom: top_dtype%array_i, top_dtype%nested%nest2%array_j, top_dtype%nested%nest%array_ptr) &
+!$omp map(tofrom: top_dtype2%array_i, top_dtype2%nested%nest2%array_j, top_dtype2%nested%nest%array_ptr)
+ do i = 1, 10
+ top_dtype%nested%nest%array_ptr(i) = i
+ top_dtype%nested%nest2%array_j(i) = i
+ top_dtype%array_i(i) = i
+ top_dtype2%nested%nest%array_ptr(i) = i
+ top_dtype2%nested%nest2%array_j(i) = i
+ top_dtype2%array_i(i) = i
+ end do
+!$omp end target
+
+ print *, top_dtype%nested%nest%array_ptr
+ print *, top_dtype%nested%nest2%array_j
+ print *, top_dtype%array_i
+
+ print *, top_dtype2%nested%nest%array_ptr
+ print *, top_dtype2%nested%nest2%array_j
+ print *, top_dtype2%array_i
+end program main
+
+!CHECK: 1 2 3 4 5 6 7 8 9 10
+!CHECK: 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.
+!CHECK: 1 2 3 4 5 6 7 8 9 10
+!CHECK: 1 2 3 4 5 6 7 8 9 10
+!CHECK: 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.
+!CHECK: 1 2 3 4 5 6 7 8 9 10
diff --git a/offload/test/offloading/fortran/target-map-multi-alloca-dtypes-with-multi-mixed-members.f90 b/offload/test/offloading/fortran/target-map-multi-alloca-dtypes-with-multi-mixed-members.f90
new file mode 100644
index 00000000000000..7f1eda63d9d48b
--- /dev/null
+++ b/offload/test/offloading/fortran/target-map-multi-alloca-dtypes-with-multi-mixed-members.f90
@@ -0,0 +1,82 @@
+! Offloading test checking interaction of an explicit member map of mixed
+! allocatable and non-allocatable components of a nested derived types.
+!
+! NOTE: Unfortunately this test loses a bit of its bite as we do not currently
+! support linking against an offload compiled fortran runtime library which
+! means allocatable scalar assignment isn't going to work in target regions.
+! REQUIRES: flang, amdgpu
+
+! RUN: %libomptarget-compile-fortran-run-and-check-generic
+program main
+ type :: bottom_layer1
+ real(4) :: i4
+ real(4), allocatable :: j4
+ real(4) :: k4
+ end type bottom_layer1
+
+ type :: bottom_layer2
+ integer(4) :: i3
+ integer(4) :: j3
+ integer(4), allocatable :: k3
+ end type bottom_layer2
+
+ type :: middle_layer
+ real(4) :: array_i2(10)
+ real(4) :: i2
+ real(4), allocatable :: array_j2(:)
+ type(bottom_layer1) :: nest
+ type(bottom_layer2), allocatable :: nest2
+ end type middle_layer
+
+ type :: top_layer
+ real(4) :: i
+ integer(4) :: array_i(10)
+ real(4) :: j
+ integer, allocatable :: array_j(:)
+ integer(4) :: k
+ type(middle_layer) :: nested
+ end type top_layer
+
+ type(top_layer), allocatable :: top_dtype
+
+ allocate(top_dtype)
+ allocate(top_dtype%array_j(10))
+ allocate(top_dtype%nested%nest2)
+ allocate(top_dtype%nested%array_j2(10))
+
+!$omp target map(tofrom: top_dtype%nested%nest%i4, top_dtype%nested%array_j2) &
+!$omp map(tofrom: top_dtype%nested%nest%k4, top_dtype%array_i, top_dtype%nested%nest2%i3) &
+!$omp map(tofrom: top_dtype%nested%i2, top_dtype%nested%nest2%j3, top_dtype%array_j)
+ top_dtype%nested%nest%i4 = 10
+ top_dtype%nested%nest%k4 = 10
+ top_dtype%nested%nest2%i3 = 20
+ top_dtype%nested%nest2%j3 = 40
+
+ top_dtype%nested%i2 = 200
+
+ do i = 1, 10
+ top_dtype%array_j(i) = i
+ top_dtype%array_i(i) = i
+ top_dtype%nested%array_j2(i) = i
+ end do
+!$omp end target
+
+ print *, top_dtype%nested%nest%i4
+ print *, top_dtype%nested%nest%k4
+ print *, top_dtype%nested%nest2%i3
+ print *, top_dtype%nested%nest2%j3
+
+ print *, top_dtype%nested%i2
+ print *, top_dtype%array_i
+ print *, top_dtype%array_j
+ print *, top_dtype%nested%array_j2
+end program main
+
+!CHECK: 10.
+!CHECK: 10.
+!CHECK: 20
+!CHECK: 40
+!CHECK: 200.
+!CHECK: 1 2 3 4 5 6 7 8 9 10
+!CHECK: 1 2 3 4 5 6 7 8 9 10
+!CHECK: 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.
diff --git a/offload/test/offloading/fortran/target-map-nested-alloca-dtype-3d-alloca-array-bounds.f90 b/offload/test/offloading/fortran/target-map-nested-alloca-dtype-3d-alloca-array-bounds.f90
new file mode 100644
index 00000000000000..a03e8d137ce8a9
--- /dev/null
+++ b/offload/test/offloading/fortran/target-map-nested-alloca-dtype-3d-alloca-array-bounds.f90
@@ -0,0 +1,51 @@
+! Offloading test checking interaction of an explicit member map of an
+! allocatable 3d array within a nested allocatable derived type with
+! specified bounds
+! REQUIRES: flang, amdgpu
+
+! RUN: %libomptarget-compile-fortran-run-and-check-generic
+program main
+ type :: bottom_layer
+ real(4) :: i
+ integer(4) :: array_i(10)
+ integer, allocatable :: array_k(:,:,:)
+ integer(4) :: k
+ end type bottom_layer
+
+ type :: top_layer
+ real(4) :: i
+ integer, allocatable :: scalar
+ integer(4) :: array_i(10)
+ real(4) :: j
+ integer, allocatable :: array_j(:)
+ integer(4) :: k
+ type(bottom_layer), allocatable :: nest
+ end type top_layer
+
+ type(top_layer), allocatable :: one_l
+ integer :: inArray(3,3,3)
+ allocate(one_l)
+ allocate(one_l%nest)
+ allocate(one_l%nest%array_k(3,3,3))
+
+ do i = 1, 3
+ do j = 1, 3
+ do k = 1, 3
+ inArray(i, j, k) = 42
+ one_l%nest%array_k(i, j, k) = 0
+ end do
+ end do
+ end do
+
+!$omp target map(tofrom: one_l%nest%array_k(1:3, 1:3, 2:2)) map(to: inArray(1:3, 1:3, 1:3))
+ do j = 1, 3
+ do k = 1, 3
+ one_l%nest%array_k(k, j, 2) = inArray(k, j, 2)
+ end do
+ end do
+!$omp end target
+
+ print *, one_l%nest%array_k
+end program main
+
+!CHECK: 0 0 0 0 0 0 0 0 0 42 42 42 42 42 42 42 42 42 0 0 0 0 0 0 0 0 0
diff --git a/offload/test/offloading/fortran/target-map-nested-alloca-dtype-alloca-array-bounds.f90 b/offload/test/offloading/fortran/target-map-nested-alloca-dtype-alloca-array-bounds.f90
new file mode 100644
index 00000000000000..35b487370d1ab4
--- /dev/null
+++ b/offload/test/offloading/fortran/target-map-nested-alloca-dtype-alloca-array-bounds.f90
@@ -0,0 +1,43 @@
+! Offloading test checking interaction of an explicit member map of an
+! allocatable array within a nested allocatable derived type with specified
+! bounds
+! REQUIRES: flang, amdgpu
+
+! RUN: %libomptarget-compile-fortran-run-and-check-generic
+program main
+ type :: bottom_layer
+ real(4) :: i
+ integer(4) :: array_i(10)
+ integer, allocatable :: array_k(:)
+ integer(4) :: k
+ end type bottom_layer
+
+ type :: top_layer
+ real(4) :: i
+ integer, allocatable :: scalar
+ integer(4) :: array_i(10)
+ real(4) :: j
+ integer, allocatable :: array_j(:)
+ integer(4) :: k
+ type(bottom_layer), allocatable :: nest
+ end type top_layer
+
+ type(top_layer), allocatable :: one_l
+ allocate(one_l)
+ allocate(one_l%nest)
+ allocate(one_l%nest%array_k(10))
+
+ do index = 1, 10
+ one_l%nest%array_k(index) = 0
+ end do
+
+!$omp target map(tofrom: one_l%nest%array_k(2:6))
+ do index = 2, 6
+ one_l%nest%array_k(index) = index
+ end do
+!$omp end target
+
+ print *, one_l%nest%array_k
+end program main
+
+!CHECK: 0 2 3 4 5 6 0 0 0 0
diff --git a/offload/test/offloading/fortran/target-map-nested-dtype-3d-alloca-array-with-bounds.f90 b/offload/test/offloading/fortran/target-map-nested-dtype-3d-alloca-array-with-bounds.f90
new file mode 100644
index 00000000000000..5aa5a094824a80
--- /dev/null
+++ b/offload/test/offloading/fortran/target-map-nested-dtype-3d-alloca-array-with-bounds.f90
@@ -0,0 +1,50 @@
+! Offload test that checks an allocatable array can be mapped with a specified
+! 3-D bounds when contained within a nested derived type and mapped via member
+! mapping.
+! REQUIRES: flang, amdgpu
+
+! RUN: %libomptarget-compile-fortran-run-and-check-generic
+program main
+ type :: bottom_layer
+ real(4) :: i
+ integer(4) :: array_i(10)
+ integer, allocatable :: array_k(:,:,:)
+ integer(4) :: k
+ end type bottom_layer
+
+ type :: top_layer
+ real(4) :: i
+ integer, allocatable :: scalar
+ integer(4) :: array_i(10)
+ real(4) :: j
+ integer, allocatable :: array_j(:)
+ integer(4) :: k
+ type(bottom_layer) :: nest
+ end type top_layer
+
+ type(top_layer) :: one_l
+ integer :: inArray(3,3,3)
+
+ allocate(one_l%nest%array_k(3,3,3))
+
+ do i = 1, 3
+ do j = 1, 3
+ do k = 1, 3
+ inArray(i, j, k) = 42
+ one_l%nest%array_k(i, j, k) = 0
+ end do
+ end do
+ end do
+
+!$omp target map(tofrom: one_l%nest%array_k(1:3, 1:3, 2:2)) map(to: inArray(1:3, 1:3, 1:3))
+ do j = 1, 3
+ do k = 1, 3
+ one_l%nest%array_k(k, j, 2) = inArray(k, j, 2)
+ end do
+ end do
+!$omp end target
+
+ print *, one_l%nest%array_k
+end program main
+
+!CHECK: 0 0 0 0 0 0 0 0 0 42 42 42 42 42 42 42 42 42 0 0 0 0 0 0 0 0 0
diff --git a/offload/test/offloading/fortran/target-map-nested-dtype-alloca-and-non-alloca-array.f90 b/offload/test/offloading/fortran/target-map-nested-dtype-alloca-and-non-alloca-array.f90
new file mode 100644
index 00000000000000..1bbf25e0b0aa1a
--- /dev/null
+++ b/offload/test/offloading/fortran/target-map-nested-dtype-alloca-and-non-alloca-array.f90
@@ -0,0 +1,47 @@
+! Offload test that checks an allocatable array can be mapped via member
+! mapping alongside a non-allocatable array when both are contained within a
+! nested derived type.
+! REQUIRES: flang, amdgpu
+
+! RUN: %libomptarget-compile-fortran-run-and-check-generic
+program main
+ type :: bottom_layer
+ real(4) :: i
+ integer, allocatable :: scalar_i
+ integer(4) :: array_i(10)
+ integer, allocatable :: array_k(:)
+ integer(4) :: k
+ end type bottom_layer
+
+ type :: one_layer
+ real(4) :: i
+ integer, allocatable :: scalar
+ integer(4) :: array_i(10)
+ real(4) :: j
+ integer, allocatable :: array_j(:)
+ integer(4) :: k
+ type(bottom_layer) :: nest
+ end type one_layer
+
+ type(one_layer) :: one_l
+
+ allocate(one_l%nest%array_k(10))
+ allocate(one_l%nest%scalar_i)
+
+ do i = 1, 10
+ one_l%nest%array_i(i) = i
+ end do
+
+ !$omp target map(tofrom: one_l%nest%array_i, one_l%nest%array_k)
+ do i = 1, 10
+ one_l%nest%array_k(i) = one_l%nest%array_i(i) + i
+ end do
+ !$omp end target
+
+ print *, one_l%nest%array_k
+ print *, one_l%nest%array_i
+end program main
+
+!CHECK: 2 4 6 8 10 12 14 16 18 20
+!CHECK: 1 2 3 4 5 6 7 8 9 10
+
diff --git a/offload/test/offloading/fortran/target-map-nested-dtype-alloca-array-and-non-alloca-dtype.f90 b/offload/test/offloading/fortran/target-map-nested-dtype-alloca-array-and-non-alloca-dtype.f90
new file mode 100644
index 00000000000000..f278c37e99903e
--- /dev/null
+++ b/offload/test/offloading/fortran/target-map-nested-dtype-alloca-array-and-non-alloca-dtype.f90
@@ -0,0 +1,51 @@
+! Offload test that checks an allocatable array can be mapped alongside a
+! non-allocatable derived type when both are contained within a nested derived
+! type.
+! REQUIRES: flang, amdgpu
+
+! RUN: %libomptarget-compile-fortran-run-and-check-generic
+program main
+ type :: bottom_layer
+ real(4) :: i
+ integer(4) :: array_i(10)
+ integer(4) :: k
+ end type bottom_layer
+
+ type :: middle_layer
+ real(4) :: i
+ integer(4) :: array_i(10)
+ type(bottom_layer) :: nest2
+ integer, allocatable :: array_k(:)
+ integer(4) :: k
+ end type middle_layer
+
+ type :: top_layer
+ real(4) :: i
+ integer, allocatable :: scalar
+ integer(4) :: array_i(10)
+ real(4) :: j
+ integer, allocatable :: array_j(:)
+ integer(4) :: k
+ type(middle_layer) :: nest
+ end type top_layer
+
+ type(top_layer) :: one_l
+
+ allocate(one_l%nest%array_k(10))
+
+ do i = 1, 10
+ one_l%nest%nest2%array_i(i) = i
+ end do
+
+ !$omp target map(tofrom: one_l%nest%nest2, one_l%nest%array_k)
+ do i = 1, 10
+ one_l%nest%array_k(i) = one_l%nest%nest2%array_i(i) + i
+ end do
+ !$omp end target
+
+ print *, one_l%nest%nest2%array_i
+ print *, one_l%nest%array_k
+end program main
+
+!CHECK: 1 2 3 4 5 6 7 8 9 10
+!CHECK: 2 4 6 8 10 12 14 16 18 20
diff --git a/offload/test/offloading/fortran/target-map-nested-dtype-alloca-array-with-bounds.f90 b/offload/test/offloading/fortran/target-map-nested-dtype-alloca-array-with-bounds.f90
new file mode 100644
index 00000000000000..84328f79ef1c90
--- /dev/null
+++ b/offload/test/offloading/fortran/target-map-nested-dtype-alloca-array-with-bounds.f90
@@ -0,0 +1,43 @@
+! Offload test that checks an allocatable array can be mapped with a specified
+! 1-D bounds when contained within a nested derived type and mapped via member
+! mapping.
+! REQUIRES: flang, amdgpu
+
+! RUN: %libomptarget-compile-fortran-run-and-check-generic
+program main
+ type :: bottom_layer
+ real(4) :: i
+ integer(4) :: array_i(10)
+ integer, allocatable :: array_k(:)
+ integer(4) :: k
+ end type bottom_layer
+
+ type :: top_layer
+ real(4) :: i
+ integer, allocatable :: scalar
+ integer(4) :: array_i(10)
+ real(4) :: j
+ integer, allocatable :: array_j(:)
+ integer(4) :: k
+ type(bottom_layer) :: nest
+ end type top_layer
+
+ type(top_layer) :: one_l
+
+ allocate(one_l%nest%array_k(10))
+
+ do index = 1, 10
+ one_l%nest%array_k(index) = 0
+ end do
+
+!$omp target map(tofrom: one_l%nest%array_k(2:6))
+ do index = 2, 6
+ one_l%nest%array_k(index) = index
+ end do
+!$omp end target
+
+print *, one_l%nest%array_k
+
+end program main
+
+!CHECK: 0 2 3 4 5 6 0 0 0 0
diff --git a/offload/test/offloading/fortran/target-map-nested-dtype-alloca-array.f90 b/offload/test/offloading/fortran/target-map-nested-dtype-alloca-array.f90
new file mode 100644
index 00000000000000..7d0b06dd67f020
--- /dev/null
+++ b/offload/test/offloading/fortran/target-map-nested-dtype-alloca-array.f90
@@ -0,0 +1,37 @@
+! Offload test that checks an allocatable array contained within a nested
+! derived type can be mapped correctly via member mapping and then written to.
+! REQUIRES: flang, amdgpu
+
+! RUN: %libomptarget-compile-fortran-run-and-check-generic
+program main
+ type :: bottom_layer
+ real(4) :: i
+ integer(4) :: array_i(10)
+ integer, allocatable :: array_k(:)
+ integer(4) :: k
+ end type bottom_layer
+
+ type :: one_layer
+ real(4) :: i
+ integer, allocatable :: scalar
+ integer(4) :: array_i(10)
+ real(4) :: j
+ integer, allocatable :: array_j(:)
+ integer(4) :: k
+ type(bottom_layer) :: nest
+ end type one_layer
+
+ type(one_layer) :: one_l
+
+ allocate(one_l%nest%array_k(10))
+
+!$omp target map(tofrom: one_l%nest%array_k)
+ do i = 1, 10
+ one_l%nest%array_k(i) = i
+ end do
+!$omp end target
+
+ print *, one_l%nest%array_k
+end program main
+
+!CHECK: 1 2 3 4 5 6 7 8 9 10
diff --git a/offload/test/offloading/fortran/target-map-nested-dtype-complex-member.f90 b/offload/test/offloading/fortran/target-map-nested-dtype-complex-member.f90
index becc88d3157c8b..e1c5fbba538734 100644
--- a/offload/test/offloading/fortran/target-map-nested-dtype-complex-member.f90
+++ b/offload/test/offloading/fortran/target-map-nested-dtype-complex-member.f90
@@ -1,6 +1,5 @@
-! Offloading test checking interaction of an
-! nested derived type member map of a complex
-! number member
+! Offloading test checking interaction of an nested derived type member map of
+! a complex number member
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/target-map-nested-dtype-derived-member.f90 b/offload/test/offloading/fortran/target-map-nested-dtype-derived-member.f90
index c5f79de22b2963..3d5cb95a78c85b 100644
--- a/offload/test/offloading/fortran/target-map-nested-dtype-derived-member.f90
+++ b/offload/test/offloading/fortran/target-map-nested-dtype-derived-member.f90
@@ -1,7 +1,5 @@
-! Offloading test checking interaction of an
-! nested derived type member map with the
-! inclusion of an entire nested derived
-! type being mapped
+! Offloading test checking interaction of an nested derived type member map
+! with the inclusion of an entire nested derived type being mapped
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/target-map-nested-dtype-multi-member.f90 b/offload/test/offloading/fortran/target-map-nested-dtype-multi-member.f90
index b3579c39f7f66b..b8153940fbaa2f 100644
--- a/offload/test/offloading/fortran/target-map-nested-dtype-multi-member.f90
+++ b/offload/test/offloading/fortran/target-map-nested-dtype-multi-member.f90
@@ -1,6 +1,5 @@
-! Offloading test checking interaction of an
-! explicit member map from a small nested
-! derived type
+! Offloading test checking interaction of an explicit member map from a small
+! nested derived type
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/target-map-nested-dtype-single-member.f90 b/offload/test/offloading/fortran/target-map-nested-dtype-single-member.f90
index 20c245a5877c53..498b461ca25f27 100644
--- a/offload/test/offloading/fortran/target-map-nested-dtype-single-member.f90
+++ b/offload/test/offloading/fortran/target-map-nested-dtype-single-member.f90
@@ -1,6 +1,5 @@
-! Offloading test checking interaction of an
-! single explicit member map from a nested
-! derived type.
+! Offloading test checking interaction of an single explicit member map from a
+! nested derived type.
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/target-map-pointer-scopes-enter-exit.f90 b/offload/test/offloading/fortran/target-map-pointer-scopes-enter-exit.f90
index 2dc03641f8a696..f5f284caed64f1 100644
--- a/offload/test/offloading/fortran/target-map-pointer-scopes-enter-exit.f90
+++ b/offload/test/offloading/fortran/target-map-pointer-scopes-enter-exit.f90
@@ -1,5 +1,5 @@
-! Offloading test checking interaction of pointers
-! with target in different scopes
+! Offloading test checking interaction of pointers with target in different
+! scopes
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/target-map-pointer-target-array-section-3d-bounds.f90 b/offload/test/offloading/fortran/target-map-pointer-target-array-section-3d-bounds.f90
index 2b2c60f5d4b50e..6d9c497134ffb5 100644
--- a/offload/test/offloading/fortran/target-map-pointer-target-array-section-3d-bounds.f90
+++ b/offload/test/offloading/fortran/target-map-pointer-target-array-section-3d-bounds.f90
@@ -1,6 +1,5 @@
-! Offloading test checking interaction of pointer
-! and target with target where 3-D bounds have
-! been specified
+! Offloading test checking interaction of pointer and target with target where
+! 3-D bounds have been specified
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/target-map-pointer-target-scopes.f90 b/offload/test/offloading/fortran/target-map-pointer-target-scopes.f90
index fcbcf024d9c9df..323f0e055fb546 100644
--- a/offload/test/offloading/fortran/target-map-pointer-target-scopes.f90
+++ b/offload/test/offloading/fortran/target-map-pointer-target-scopes.f90
@@ -1,5 +1,5 @@
-! Offloading test checking interaction of pointer
-! and target with target across multiple scopes
+! Offloading test checking interaction of pointer and target with target across
+! multiple scopes
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/target-map-pointer-to-dtype-allocatable-member.f90 b/offload/test/offloading/fortran/target-map-pointer-to-dtype-allocatable-member.f90
new file mode 100644
index 00000000000000..8e1e68528943fd
--- /dev/null
+++ b/offload/test/offloading/fortran/target-map-pointer-to-dtype-allocatable-member.f90
@@ -0,0 +1,45 @@
+! Offloading test checking interaction of implicit captured of a pointer
+! targeting an allocatable member of a derived type, alongside the explicit
+! map of the derived type and allocatable data via target enter and exit
+! directives
+! REQUIRES: flang, amdgpu
+
+! RUN: %libomptarget-compile-fortran-run-and-check-generic
+module dtype
+ type :: my_dtype
+ integer :: s, e
+ integer,dimension(:),allocatable :: values
+ end type
+end module
+
+program offload_types
+ use dtype
+
+ type(my_dtype),target :: my_instance
+ integer,dimension(:),pointer :: values_ptr
+ integer :: i
+
+ allocate(my_instance%values(20))
+ my_instance%s=1
+ my_instance%e=20
+
+ values_ptr => my_instance%values
+
+ !$omp target enter data map(to:my_instance, my_instance%values)
+
+ !$omp target
+ do i = 1,20
+ values_ptr(i) = i
+ end do
+ !$omp end target
+
+ !$omp target exit data map(from:my_instance%values)
+
+ write(*,*) my_instance%values
+
+ !$omp target exit data map(release:my_instance)
+
+ deallocate(my_instance%values)
+end program
+
+!CHECK: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
diff --git a/offload/test/offloading/fortran/target-map-second-common-block-member.f90 b/offload/test/offloading/fortran/target-map-second-common-block-member.f90
index fce876cfb02136..432c6e1f82b9f8 100644
--- a/offload/test/offloading/fortran/target-map-second-common-block-member.f90
+++ b/offload/test/offloading/fortran/target-map-second-common-block-member.f90
@@ -1,6 +1,5 @@
-! Offloading test checking interaction of
-! mapping a member of a common block to a
-! target region
+! Offloading test checking interaction of mapping a member of a common block to
+! a target region
! REQUIRES: flang, amdgcn-amd-amdhsa
! UNSUPPORTED: nvptx64-nvidia-cuda
! UNSUPPORTED: nvptx64-nvidia-cuda-LTO
diff --git a/offload/test/offloading/fortran/target-map-two-dtype-explicit-member.f90 b/offload/test/offloading/fortran/target-map-two-dtype-explicit-member.f90
index 2d9f3cdfccc91d..0fe153189f1b46 100644
--- a/offload/test/offloading/fortran/target-map-two-dtype-explicit-member.f90
+++ b/offload/test/offloading/fortran/target-map-two-dtype-explicit-member.f90
@@ -1,6 +1,5 @@
-! Offloading test checking interaction of two
-! derived type's with one explicit member
-! each being mapped with bounds to target
+! Offloading test checking interaction of two derived type's with one explicit
+! member each being mapped with bounds to target
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/target-map-two-dtype-individual-member-array-1D-bounds.f90 b/offload/test/offloading/fortran/target-map-two-dtype-individual-member-array-1D-bounds.f90
index 26d030c2f042d6..261443a4e4e964 100644
--- a/offload/test/offloading/fortran/target-map-two-dtype-individual-member-array-1D-bounds.f90
+++ b/offload/test/offloading/fortran/target-map-two-dtype-individual-member-array-1D-bounds.f90
@@ -1,7 +1,5 @@
-! Offloading test checking interaction of two
-! derived type's with a single explicit array
-! member each being mapped with bounds to
-! target
+! Offloading test checking interaction of two derived type's with a single
+! explicit array member each being mapped with bounds to target
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/target-map-two-dtype-mixed-implicit-explicit-capture-1.f90 b/offload/test/offloading/fortran/target-map-two-dtype-mixed-implicit-explicit-capture-1.f90
index 43cdf0497c57de..7d3a3eca340597 100644
--- a/offload/test/offloading/fortran/target-map-two-dtype-mixed-implicit-explicit-capture-1.f90
+++ b/offload/test/offloading/fortran/target-map-two-dtype-mixed-implicit-explicit-capture-1.f90
@@ -1,6 +1,5 @@
-! Offloading test checking interaction of two
-! derived type's with a mix of explicit and
-! implicit member mapping to target
+! Offloading test checking interaction of two derived type's with a mix of
+! explicit and implicit member mapping to target
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/target-map-two-dtype-mixed-implicit-explicit-capture-2.f90 b/offload/test/offloading/fortran/target-map-two-dtype-mixed-implicit-explicit-capture-2.f90
index 336e182f8a16b8..8f0bae32709b86 100644
--- a/offload/test/offloading/fortran/target-map-two-dtype-mixed-implicit-explicit-capture-2.f90
+++ b/offload/test/offloading/fortran/target-map-two-dtype-mixed-implicit-explicit-capture-2.f90
@@ -1,7 +1,5 @@
-! Offloading test checking interaction of two
-! derived type's with a mix of explicit and
-! implicit member mapping of arrays to target
-! one with bounds.
+! Offloading test checking interaction of two derived type's with a mix of
+! explicit and implicit member mapping of arrays to target one with bounds.
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/target-map-two-dtype-multi-member-array-1D-bounds.f90 b/offload/test/offloading/fortran/target-map-two-dtype-multi-member-array-1D-bounds.f90
index 308d6a0c361002..4726093c3657ef 100644
--- a/offload/test/offloading/fortran/target-map-two-dtype-multi-member-array-1D-bounds.f90
+++ b/offload/test/offloading/fortran/target-map-two-dtype-multi-member-array-1D-bounds.f90
@@ -1,7 +1,5 @@
-! Offloading test checking interaction of two
-! derived type's with two explicit array
-! members each being mapped with bounds to
-! target
+! Offloading test checking interaction of two derived type's with two explicit
+! array members each being mapped with bounds to target
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/target-map-two-nested-dtype-member-array-map.f90 b/offload/test/offloading/fortran/target-map-two-nested-dtype-member-array-map.f90
index 1a59a7c95b9c0a..ef105839a7e4a3 100644
--- a/offload/test/offloading/fortran/target-map-two-nested-dtype-member-array-map.f90
+++ b/offload/test/offloading/fortran/target-map-two-nested-dtype-member-array-map.f90
@@ -1,5 +1,5 @@
-! Offloading test checking interaction of an
-! explicit member map utilising array bounds
+! Offloading test checking interaction of an explicit member map utilising
+! array bounds
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/target-nested-target-data.f90 b/offload/test/offloading/fortran/target-nested-target-data.f90
index 6041433afbdc6e..1eb52caf278b7d 100644
--- a/offload/test/offloading/fortran/target-nested-target-data.f90
+++ b/offload/test/offloading/fortran/target-nested-target-data.f90
@@ -1,5 +1,4 @@
-! Offloading test for target nested inside
-! a target data region
+! Offloading test for target nested inside a target data region
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
diff --git a/offload/test/offloading/fortran/target-region-implicit-array.f90 b/offload/test/offloading/fortran/target-region-implicit-array.f90
index 22d0c5ea655fcd..e3852569a5a82a 100644
--- a/offload/test/offloading/fortran/target-region-implicit-array.f90
+++ b/offload/test/offloading/fortran/target-region-implicit-array.f90
@@ -1,5 +1,5 @@
-! Basic offloading test of a regular array explicitly
-! passed within a target region
+! Basic offloading test of a regular array explicitly passed within a target
+! region
! REQUIRES: flang, amdgpu
! RUN: %libomptarget-compile-fortran-run-and-check-generic
>From 7d27486647bbaee3936fe81351e18c89e192f368 Mon Sep 17 00:00:00 2001
From: agozillon <Andrew.Gozillon at amd.com>
Date: Fri, 4 Oct 2024 13:03:22 -0500
Subject: [PATCH 2/3] [OpenMP][MLIR] Descriptor explicit member map lowering
changes
This is one of 3 PRs in a PR stack that aims to add support for explicit mapping of
allocatable members in derived types.
The primary changes in this PR are the OpenMPToLLVMIRTranslation.cpp changes,
which are small and seek to alter the current member mapping to add an
additional map insertion for pointers. Effectively, if the member is a pointer
(currently indicated by having a varPtrPtr field) we add an additional map for
the pointer and then alter the subsequent mapping of the member (the data)
to utilise the member rather than the parents base pointer. This appears to be
necessary in certain cases when mapping pointer data within record types to
avoid segfaulting on device (due to incorrect data mapping). In general this
record type mapping may be simplifiable in the future.
There are also additions of tests which should help to showcase the affect
of the changes above.
---
mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td | 2 +-
mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp | 58 +++------
.../OpenMP/OpenMPToLLVMIRTranslation.cpp | 81 ++++++++-----
mlir/test/Dialect/OpenMP/ops.mlir | 4 +-
...t-nested-ptr-record-type-mapping-host.mlir | 66 ++++++++++
...arget-nested-record-type-mapping-host.mlir | 2 +-
...get-record-type-with-ptr-member-host.mlir} | 114 ++++++++++--------
7 files changed, 197 insertions(+), 130 deletions(-)
create mode 100644 mlir/test/Target/LLVMIR/omptarget-nested-ptr-record-type-mapping-host.mlir
rename mlir/test/Target/LLVMIR/{omptarget-fortran-allocatable-types-host.mlir => omptarget-record-type-with-ptr-member-host.mlir} (58%)
diff --git a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td
index 5fd8184fe0e0f7..9e8aa5d1e786ae 100644
--- a/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td
+++ b/mlir/include/mlir/Dialect/OpenMP/OpenMPOps.td
@@ -895,7 +895,7 @@ def MapInfoOp : OpenMP_Op<"map.info", [AttrSizedOperandSegments]> {
TypeAttr:$var_type,
Optional<OpenMP_PointerLikeType>:$var_ptr_ptr,
Variadic<OpenMP_PointerLikeType>:$members,
- OptionalAttr<AnyIntElementsAttr>:$members_index,
+ OptionalAttr<IndexListArrayAttr>:$members_index,
Variadic<OpenMP_MapBoundsType>:$bounds, /* rank-0 to rank-{n-1} */
OptionalAttr<UI64Attr>:$map_type,
OptionalAttr<VariableCaptureKindAttr>:$map_capture_type,
diff --git a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
index 4a27a5ed8eb74b..a6abe305263e58 100644
--- a/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
+++ b/mlir/lib/Dialect/OpenMP/IR/OpenMPDialect.cpp
@@ -1395,16 +1395,15 @@ static void printMapClause(OpAsmPrinter &p, Operation *op,
}
static ParseResult parseMembersIndex(OpAsmParser &parser,
- DenseIntElementsAttr &membersIdx) {
- SmallVector<APInt> values;
- int64_t value;
- int64_t shape[2] = {0, 0};
- unsigned shapeTmp = 0;
+ ArrayAttr &membersIdx) {
+ SmallVector<Attribute> values, memberIdxs;
+
auto parseIndices = [&]() -> ParseResult {
+ int64_t value;
if (parser.parseInteger(value))
return failure();
- shapeTmp++;
- values.push_back(APInt(32, value, /*isSigned=*/true));
+ values.push_back(IntegerAttr::get(parser.getBuilder().getIntegerType(64),
+ APInt(64, value, /*isSigned=*/false)));
return success();
};
@@ -1418,52 +1417,29 @@ static ParseResult parseMembersIndex(OpAsmParser &parser,
if (failed(parser.parseRSquare()))
return failure();
- // Only set once, if any indices are not the same size
- // we error out in the next check as that's unsupported
- if (shape[1] == 0)
- shape[1] = shapeTmp;
-
- // Verify that the recently parsed list is equal to the
- // first one we parsed, they must be equal lengths to
- // keep the rectangular shape DenseIntElementsAttr
- // requires
- if (shapeTmp != shape[1])
- return failure();
-
- shapeTmp = 0;
- shape[0]++;
+ memberIdxs.push_back(ArrayAttr::get(parser.getContext(), values));
+ values.clear();
} while (succeeded(parser.parseOptionalComma()));
- if (!values.empty()) {
- ShapedType valueType =
- VectorType::get(shape, IntegerType::get(parser.getContext(), 32));
- membersIdx = DenseIntElementsAttr::get(valueType, values);
- }
+ if (!memberIdxs.empty())
+ membersIdx = ArrayAttr::get(parser.getContext(), memberIdxs);
return success();
}
static void printMembersIndex(OpAsmPrinter &p, MapInfoOp op,
- DenseIntElementsAttr membersIdx) {
- llvm::ArrayRef<int64_t> shape = membersIdx.getShapedType().getShape();
- assert(shape.size() <= 2);
-
+ ArrayAttr membersIdx) {
if (!membersIdx)
return;
- for (int i = 0; i < shape[0]; ++i) {
+ llvm::interleaveComma(membersIdx, p, [&p](Attribute v) {
p << "[";
- int rowOffset = i * shape[1];
- for (int j = 0; j < shape[1]; ++j) {
- p << membersIdx.getValues<int32_t>()[rowOffset + j];
- if ((j + 1) < shape[1])
- p << ",";
- }
+ auto memberIdx = cast<ArrayAttr>(v);
+ llvm::interleaveComma(memberIdx.getValue(), p, [&p](Attribute v2) {
+ p << cast<IntegerAttr>(v2).getInt();
+ });
p << "]";
-
- if ((i + 1) < shape[0])
- p << ", ";
- }
+ });
}
static void printCaptureType(OpAsmPrinter &p, Operation *op,
diff --git a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
index da11ee9960e1f9..64f4b6ba982ff1 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
@@ -2878,46 +2878,36 @@ static int getMapDataMemberIdx(MapInfoData &mapData, omp::MapInfoOp memberOp) {
static omp::MapInfoOp getFirstOrLastMappedMemberPtr(omp::MapInfoOp mapInfo,
bool first) {
- DenseIntElementsAttr indexAttr = mapInfo.getMembersIndexAttr();
-
+ ArrayAttr indexAttr = mapInfo.getMembersIndexAttr();
// Only 1 member has been mapped, we can return it.
if (indexAttr.size() == 1)
- if (auto mapOp =
- dyn_cast<omp::MapInfoOp>(mapInfo.getMembers()[0].getDefiningOp()))
- return mapOp;
+ return cast<omp::MapInfoOp>(mapInfo.getMembers()[0].getDefiningOp());
- llvm::ArrayRef<int64_t> shape = indexAttr.getShapedType().getShape();
- llvm::SmallVector<size_t> indices(shape[0]);
+ llvm::SmallVector<size_t> indices(indexAttr.size());
std::iota(indices.begin(), indices.end(), 0);
llvm::sort(indices.begin(), indices.end(),
[&](const size_t a, const size_t b) {
- auto indexValues = indexAttr.getValues<int32_t>();
- for (int i = 0; i < shape[1]; ++i) {
- int aIndex = indexValues[a * shape[1] + i];
- int bIndex = indexValues[b * shape[1] + i];
+ auto memberIndicesA = cast<ArrayAttr>(indexAttr[a]);
+ auto memberIndicesB = cast<ArrayAttr>(indexAttr[b]);
+ for (const auto it : llvm::zip(memberIndicesA, memberIndicesB)) {
+ int64_t aIndex = cast<IntegerAttr>(std::get<0>(it)).getInt();
+ int64_t bIndex = cast<IntegerAttr>(std::get<1>(it)).getInt();
if (aIndex == bIndex)
continue;
- if (aIndex != -1 && bIndex == -1)
- return false;
-
- if (aIndex == -1 && bIndex != -1)
- return true;
-
- // A is earlier in the record type layout than B
if (aIndex < bIndex)
return first;
- if (bIndex < aIndex)
+ if (aIndex > bIndex)
return !first;
}
- // Iterated the entire list and couldn't make a decision, all
- // elements were likely the same. Return false, since the sort
- // comparator should return false for equal elements.
- return false;
+ // Iterated the up until the end of the smallest member and
+ // they were found to be equal up to that point, so select
+ // the member with the lowest index count, so the "parent"
+ return memberIndicesA.size() < memberIndicesB.size();
});
return llvm::cast<omp::MapInfoOp>(
@@ -3088,17 +3078,8 @@ static llvm::omp::OpenMPOffloadMappingFlags mapParentWithMembers(
/*isSigned=*/false);
combinedInfo.Sizes.push_back(size);
- // TODO: This will need to be expanded to include the whole host of logic for
- // the map flags that Clang currently supports (e.g. it should take the map
- // flag of the parent map flag, remove the OMP_MAP_TARGET_PARAM and do some
- // further case specific flag modifications). For the moment, it handles what
- // we support as expected.
- llvm::omp::OpenMPOffloadMappingFlags mapFlag =
- llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO;
-
llvm::omp::OpenMPOffloadMappingFlags memberOfFlag =
ompBuilder.getMemberOfFlag(combinedInfo.BasePointers.size() - 1);
- ompBuilder.setCorrectMemberOfFlag(mapFlag, memberOfFlag);
// This creates the initial MEMBER_OF mapping that consists of
// the parent/top level container (same as above effectively, except
@@ -3107,6 +3088,12 @@ static llvm::omp::OpenMPOffloadMappingFlags mapParentWithMembers(
// only relevant if the structure in its totality is being mapped,
// otherwise the above suffices.
if (!parentClause.getPartialMap()) {
+ // TODO: This will need to be expanded to include the whole host of logic
+ // for the map flags that Clang currently supports (e.g. it should do some
+ // further case specific flag modifications). For the moment, it handles
+ // what we support as expected.
+ llvm::omp::OpenMPOffloadMappingFlags mapFlag = mapData.Types[mapDataIndex];
+ ompBuilder.setCorrectMemberOfFlag(mapFlag, memberOfFlag);
combinedInfo.Types.emplace_back(mapFlag);
combinedInfo.DevicePointers.emplace_back(
llvm::OpenMPIRBuilder::DeviceInfoTy::None);
@@ -3157,6 +3144,31 @@ static void processMapMembersWithParent(
assert(memberDataIdx >= 0 && "could not find mapped member of structure");
+ // If we're currently mapping a pointer to a block of data, we must
+ // initially map the pointer, and then attatch/bind the data with a
+ // subsequent map to the pointer. This segment of code generates the
+ // pointer mapping, which can in certain cases be optimised out as Clang
+ // currently does in its lowering. However, for the moment we do not do so,
+ // in part as we currently have substantially less information on the data
+ // being mapped at this stage.
+ if (checkIfPointerMap(memberClause)) {
+ auto mapFlag = llvm::omp::OpenMPOffloadMappingFlags(
+ memberClause.getMapType().value());
+ mapFlag &= ~llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TARGET_PARAM;
+ mapFlag |= llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_MEMBER_OF;
+ ompBuilder.setCorrectMemberOfFlag(mapFlag, memberOfFlag);
+ combinedInfo.Types.emplace_back(mapFlag);
+ combinedInfo.DevicePointers.emplace_back(
+ llvm::OpenMPIRBuilder::DeviceInfoTy::None);
+ combinedInfo.Names.emplace_back(
+ LLVM::createMappingInformation(memberClause.getLoc(), ompBuilder));
+ combinedInfo.BasePointers.emplace_back(
+ mapData.BasePointers[mapDataIndex]);
+ combinedInfo.Pointers.emplace_back(mapData.BasePointers[memberDataIdx]);
+ combinedInfo.Sizes.emplace_back(builder.getInt64(
+ moduleTranslation.getLLVMModule()->getDataLayout().getPointerSize()));
+ }
+
// Same MemberOfFlag to indicate its link with parent and other members
// of.
auto mapFlag =
@@ -3172,7 +3184,10 @@ static void processMapMembersWithParent(
mapData.DevicePointers[memberDataIdx]);
combinedInfo.Names.emplace_back(
LLVM::createMappingInformation(memberClause.getLoc(), ompBuilder));
- combinedInfo.BasePointers.emplace_back(mapData.BasePointers[mapDataIndex]);
+ uint64_t basePointerIndex =
+ checkIfPointerMap(memberClause) ? memberDataIdx : mapDataIndex;
+ combinedInfo.BasePointers.emplace_back(
+ mapData.BasePointers[basePointerIndex]);
combinedInfo.Pointers.emplace_back(mapData.Pointers[memberDataIdx]);
combinedInfo.Sizes.emplace_back(mapData.Sizes[memberDataIdx]);
}
diff --git a/mlir/test/Dialect/OpenMP/ops.mlir b/mlir/test/Dialect/OpenMP/ops.mlir
index b606f9eb708cf3..9c9ae3fa6527e6 100644
--- a/mlir/test/Dialect/OpenMP/ops.mlir
+++ b/mlir/test/Dialect/OpenMP/ops.mlir
@@ -2633,8 +2633,8 @@ func.func @omp_map_with_members(%arg0: !llvm.ptr, %arg1: !llvm.ptr, %arg2: !llvm
// CHECK: %[[MAP4:.*]] = omp.map.info var_ptr(%[[ARG4]] : !llvm.ptr, f32) map_clauses(from) capture(ByRef) -> !llvm.ptr {name = ""}
%mapv5 = omp.map.info var_ptr(%arg4 : !llvm.ptr, f32) map_clauses(from) capture(ByRef) -> !llvm.ptr {name = ""}
- // CHECK: %[[MAP5:.*]] = omp.map.info var_ptr(%[[ARG5]] : !llvm.ptr, !llvm.struct<(i32, struct<(i32, f32)>)>) map_clauses(from) capture(ByRef) members(%[[MAP3]], %[[MAP4]] : [1,0], [1,1] : !llvm.ptr, !llvm.ptr) -> !llvm.ptr {name = "", partial_map = true}
- %mapv6 = omp.map.info var_ptr(%arg5 : !llvm.ptr, !llvm.struct<(i32, struct<(i32, f32)>)>) map_clauses(from) capture(ByRef) members(%mapv4, %mapv5 : [1,0], [1,1] : !llvm.ptr, !llvm.ptr) -> !llvm.ptr {name = "", partial_map = true}
+ // CHECK: %[[MAP5:.*]] = omp.map.info var_ptr(%[[ARG5]] : !llvm.ptr, !llvm.struct<(i32, struct<(i32, f32)>)>) map_clauses(from) capture(ByRef) members(%[[MAP3]], %[[MAP4]] : [1, 0], [1, 1] : !llvm.ptr, !llvm.ptr) -> !llvm.ptr {name = "", partial_map = true}
+ %mapv6 = omp.map.info var_ptr(%arg5 : !llvm.ptr, !llvm.struct<(i32, struct<(i32, f32)>)>) map_clauses(from) capture(ByRef) members(%mapv4, %mapv5 : [1, 0], [1, 1] : !llvm.ptr, !llvm.ptr) -> !llvm.ptr {name = "", partial_map = true}
// CHECK: omp.target_exit_data map_entries(%[[MAP3]], %[[MAP4]], %[[MAP5]] : !llvm.ptr, !llvm.ptr, !llvm.ptr)
omp.target_exit_data map_entries(%mapv4, %mapv5, %mapv6 : !llvm.ptr, !llvm.ptr, !llvm.ptr){}
diff --git a/mlir/test/Target/LLVMIR/omptarget-nested-ptr-record-type-mapping-host.mlir b/mlir/test/Target/LLVMIR/omptarget-nested-ptr-record-type-mapping-host.mlir
new file mode 100644
index 00000000000000..5d772a13fe578a
--- /dev/null
+++ b/mlir/test/Target/LLVMIR/omptarget-nested-ptr-record-type-mapping-host.mlir
@@ -0,0 +1,66 @@
+// RUN: mlir-translate -mlir-to-llvmir %s | FileCheck %s
+
+// This test checks the offload sizes, map types and base pointers and pointers
+// provided to the OpenMP kernel argument structure are correct when lowering
+// to LLVM-IR from MLIR when performing explicit member mapping of a record type
+// that includes records with pointer members in various locations of the record
+// types hierarchy.
+
+module attributes {omp.is_target_device = false, omp.target_triples = ["amdgcn-amd-amdhsa"]} {
+ llvm.func @omp_nested_derived_type_alloca_map(%arg0: !llvm.ptr) {
+ %0 = llvm.mlir.constant(4 : index) : i64
+ %1 = llvm.mlir.constant(1 : index) : i64
+ %2 = llvm.mlir.constant(2 : index) : i64
+ %3 = llvm.mlir.constant(0 : index) : i64
+ %4 = llvm.mlir.constant(6 : index) : i64
+ %5 = omp.map.bounds lower_bound(%3 : i64) upper_bound(%0 : i64) extent(%0 : i64) stride(%1 : i64) start_idx(%3 : i64) {stride_in_bytes = true}
+ %6 = llvm.getelementptr %arg0[0, 6] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(f32, struct<(ptr, i64, i32, i8, i8, i8, i8)>, array<10 x i32>, f32, struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>, i32, struct<(f32, array<10 x i32>, struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>, i32)>)>
+ %7 = llvm.getelementptr %6[0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(f32, array<10 x i32>, struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>, i32)>
+ %8 = llvm.getelementptr %7[0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
+ %9 = omp.map.info var_ptr(%7 : !llvm.ptr, i32) var_ptr_ptr(%8 : !llvm.ptr) map_clauses(tofrom) capture(ByRef) bounds(%5) -> !llvm.ptr {name = ""}
+ %10 = omp.map.info var_ptr(%7 : !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr {name = "one_l%nest%array_k"}
+ %11 = omp.map.info var_ptr(%arg0 : !llvm.ptr, !llvm.struct<(f32, struct<(ptr, i64, i32, i8, i8, i8, i8)>, array<10 x i32>, f32, struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>, i32, struct<(f32, array<10 x i32>, struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>, i32)>)>) map_clauses(tofrom) capture(ByRef) members(%10, %9 : [6,2], [6,2,0] : !llvm.ptr, !llvm.ptr) -> !llvm.ptr {name = "one_l", partial_map = true}
+ omp.target map_entries(%10 -> %arg1, %9 -> %arg2, %11 -> %arg3 : !llvm.ptr, !llvm.ptr, !llvm.ptr) {
+ omp.terminator
+ }
+ llvm.return
+ }
+}
+
+// CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [4 x i64] [i64 0, i64 48, i64 8, i64 20]
+// CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [4 x i64] [i64 32, i64 281474976710659, i64 281474976710659, i64 281474976710675]
+
+// CHECK: define void @omp_nested_derived_type_alloca_map(ptr %[[ARG:.*]]) {
+
+// CHECK: %[[NESTED_DTYPE_MEMBER_GEP:.*]] = getelementptr { float, { ptr, i64, i32, i8, i8, i8, i8 }, [10 x i32], float, { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, i32, { float, [10 x i32], { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, i32 } }, ptr %[[ARG]], i32 0, i32 6
+// CHECK: %[[NESTED_STRUCT_PTR_MEMBER_GEP:.*]] = getelementptr { float, [10 x i32], { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, i32 }, ptr %[[NESTED_DTYPE_MEMBER_GEP]], i32 0, i32 2
+// CHECK: %[[NESTED_STRUCT_PTR_MEMBER_BADDR_GEP:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[NESTED_STRUCT_PTR_MEMBER_GEP]], i32 0, i32 0
+// CHECK: %[[NESTED_STRUCT_PTR_MEMBER_BADDR_LOAD:.*]] = load ptr, ptr %[[NESTED_STRUCT_PTR_MEMBER_BADDR_GEP]], align 8
+// CHECK: %[[ARR_OFFSET:.*]] = getelementptr inbounds i32, ptr %[[NESTED_STRUCT_PTR_MEMBER_BADDR_LOAD]], i64 0
+// CHECK: %[[DTYPE_SIZE_SEGMENT_CALC_1:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[NESTED_STRUCT_PTR_MEMBER_GEP]], i64 1
+// CHECK: %[[DTYPE_SIZE_SEGMENT_CALC_2:.*]] = ptrtoint ptr %[[DTYPE_SIZE_SEGMENT_CALC_1]] to i64
+// CHECK: %[[DTYPE_SIZE_SEGMENT_CALC_3:.*]] = ptrtoint ptr %[[NESTED_STRUCT_PTR_MEMBER_GEP]] to i64
+// CHECK: %[[DTYPE_SIZE_SEGMENT_CALC_4:.*]] = sub i64 %[[DTYPE_SIZE_SEGMENT_CALC_2]], %[[DTYPE_SIZE_SEGMENT_CALC_3]]
+// CHECK: %[[DTYPE_SIZE_SEGMENT_CALC_5:.*]] = sdiv exact i64 %[[DTYPE_SIZE_SEGMENT_CALC_4]], ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64)
+
+// CHECK: %[[BASE_PTRS:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_baseptrs, i32 0, i32 0
+// CHECK: store ptr %[[ARG]], ptr %[[BASE_PTRS]], align 8
+// CHECK: %[[OFFLOAD_PTRS:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_ptrs, i32 0, i32 0
+// CHECK: store ptr %[[NESTED_STRUCT_PTR_MEMBER_GEP]], ptr %[[OFFLOAD_PTRS]], align 8
+// CHECK: %[[OFFLOAD_SIZES:.*]] = getelementptr inbounds [4 x i64], ptr %.offload_sizes, i32 0, i32 0
+// CHECK: store i64 %[[DTYPE_SIZE_SEGMENT_CALC_5]], ptr %[[OFFLOAD_SIZES]], align 8
+
+// CHECK: %[[BASE_PTRS:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_baseptrs, i32 0, i32 1
+// CHECK: store ptr %[[ARG]], ptr %[[BASE_PTRS]], align 8
+// CHECK: %[[OFFLOAD_PTRS:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_ptrs, i32 0, i32 1
+// CHECK: store ptr %[[NESTED_STRUCT_PTR_MEMBER_GEP]], ptr %[[OFFLOAD_PTRS]], align 8
+
+// CHECK: %[[BASE_PTRS:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_baseptrs, i32 0, i32 2
+// CHECK: store ptr %[[ARG]], ptr %[[BASE_PTRS]], align 8
+// CHECK: %[[OFFLOAD_PTRS:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_ptrs, i32 0, i32 2
+// CHECK: store ptr %[[NESTED_STRUCT_PTR_MEMBER_BADDR_GEP]], ptr %[[OFFLOAD_PTRS]], align 8
+
+// CHECK: %[[BASE_PTRS:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_baseptrs, i32 0, i32 3
+// CHECK: store ptr %[[NESTED_STRUCT_PTR_MEMBER_BADDR_GEP]], ptr %[[BASE_PTRS]], align 8
+// CHECK: %[[OFFLOAD_PTRS:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_ptrs, i32 0, i32 3
+// CHECK: store ptr %[[ARR_OFFSET]], ptr %[[OFFLOAD_PTRS]], align 8
diff --git a/mlir/test/Target/LLVMIR/omptarget-nested-record-type-mapping-host.mlir b/mlir/test/Target/LLVMIR/omptarget-nested-record-type-mapping-host.mlir
index 8c1182c839a257..8837b42f70a447 100644
--- a/mlir/test/Target/LLVMIR/omptarget-nested-record-type-mapping-host.mlir
+++ b/mlir/test/Target/LLVMIR/omptarget-nested-record-type-mapping-host.mlir
@@ -21,7 +21,7 @@ llvm.func @_QQmain() {
%9 = llvm.getelementptr %4[0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(f32, array<10 x i32>, struct<(f32, i32)>, i32)>
%10 = omp.map.bounds lower_bound(%2 : i64) upper_bound(%1 : i64) extent(%0 : i64) stride(%2 : i64) start_idx(%2 : i64)
%11 = omp.map.info var_ptr(%9 : !llvm.ptr, !llvm.array<10 x i32>) map_clauses(tofrom) capture(ByRef) bounds(%10) -> !llvm.ptr
- %12 = omp.map.info var_ptr(%4 : !llvm.ptr, !llvm.struct<(f32, array<10 x i32>, struct<(f32, i32)>, i32)>) map_clauses(tofrom) capture(ByRef) members(%6, %8, %11 : [3, -1], [2, 1], [1, -1] : !llvm.ptr, !llvm.ptr, !llvm.ptr) -> !llvm.ptr {partial_map = true}
+ %12 = omp.map.info var_ptr(%4 : !llvm.ptr, !llvm.struct<(f32, array<10 x i32>, struct<(f32, i32)>, i32)>) map_clauses(tofrom) capture(ByRef) members(%6, %8, %11 : [3], [2, 1], [1] : !llvm.ptr, !llvm.ptr, !llvm.ptr) -> !llvm.ptr {partial_map = true}
omp.target map_entries(%6 -> %arg0, %8 -> %arg1, %11 -> %arg2, %12 -> %arg3 : !llvm.ptr, !llvm.ptr, !llvm.ptr, !llvm.ptr) {
omp.terminator
}
diff --git a/mlir/test/Target/LLVMIR/omptarget-fortran-allocatable-types-host.mlir b/mlir/test/Target/LLVMIR/omptarget-record-type-with-ptr-member-host.mlir
similarity index 58%
rename from mlir/test/Target/LLVMIR/omptarget-fortran-allocatable-types-host.mlir
rename to mlir/test/Target/LLVMIR/omptarget-record-type-with-ptr-member-host.mlir
index 6fe77bd228ef2f..d5ca33fb38f38e 100644
--- a/mlir/test/Target/LLVMIR/omptarget-fortran-allocatable-types-host.mlir
+++ b/mlir/test/Target/LLVMIR/omptarget-record-type-with-ptr-member-host.mlir
@@ -1,20 +1,20 @@
// RUN: mlir-translate -mlir-to-llvmir %s | FileCheck %s
// This test checks the offload sizes, map types and base pointers and pointers
-// provided to the OpenMP kernel argument structure are correct when lowering
-// to LLVM-IR from MLIR when a fortran allocatable descriptor type is provided
-// alongside the omp.map.info, the test utilises mapping of array sections,
+// provided to the OpenMP kernel argument structure are correct when lowering
+// to LLVM-IR from MLIR when a structure with a pointer member type is provided
+// alongside the omp.map.info, the test utilises mapping of array sections,
// full arrays and individual allocated scalars.
module attributes {omp.is_target_device = false, omp.target_triples = ["amdgcn-amd-amdhsa"]} {
- llvm.func @_QQmain() {
+ llvm.func @main() {
%0 = llvm.mlir.constant(5 : index) : i64
%1 = llvm.mlir.constant(2 : index) : i64
%2 = llvm.mlir.constant(1 : index) : i64
- %3 = llvm.mlir.addressof @_QFEfull_arr : !llvm.ptr
+ %3 = llvm.mlir.addressof @full_arr : !llvm.ptr
%4 = llvm.mlir.constant(1 : i64) : i64
- %5 = llvm.alloca %4 x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)> {bindc_name = "scalar"} : (i64) -> !llvm.ptr
- %6 = llvm.mlir.addressof @_QFEsect_arr : !llvm.ptr
+ %5 = llvm.alloca %4 x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)> : (i64) -> !llvm.ptr
+ %6 = llvm.mlir.addressof @sect_arr : !llvm.ptr
%7 = llvm.mlir.constant(0 : i64) : i64
%8 = llvm.getelementptr %3[0, 7, %7, 0] : (!llvm.ptr, i64) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
%9 = llvm.load %8 : !llvm.ptr -> i64
@@ -47,11 +47,11 @@ module attributes {omp.is_target_device = false, omp.target_triples = ["amdgcn-a
}
llvm.return
}
- llvm.mlir.global internal @_QFEfull_arr() {addr_space = 0 : i32} : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)> {
+ llvm.mlir.global internal @full_arr() {addr_space = 0 : i32} : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)> {
%0 = llvm.mlir.undef : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
llvm.return %0 : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
}
- llvm.mlir.global internal @_QFEsect_arr() {addr_space = 0 : i32} : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)> {
+ llvm.mlir.global internal @sect_arr() {addr_space = 0 : i32} : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)> {
%0 = llvm.mlir.undef : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
llvm.return %0 : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>
}
@@ -59,11 +59,11 @@ module attributes {omp.is_target_device = false, omp.target_triples = ["amdgcn-a
// CHECK: @[[FULL_ARR_GLOB:.*]] = internal global { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } undef
// CHECK: @[[ARR_SECT_GLOB:.*]] = internal global { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] } undef
-// CHECK: @.offload_sizes = private unnamed_addr constant [9 x i64] [i64 0, i64 48, i64 0, i64 0, i64 48, i64 0, i64 0, i64 24, i64 4]
-// CHECK: @.offload_maptypes = private unnamed_addr constant [9 x i64] [i64 32, i64 281474976710657, i64 281474976710675, i64 32, i64 1125899906842625, i64 1125899906842643, i64 32, i64 1970324836974593, i64 1970324836974611]
-// CHECK: @.offload_mapnames = private constant [9 x ptr] [ptr @{{.*}}, ptr @{{.*}}, ptr @{{.*}}, ptr @{{.*}}, ptr @{{.*}}, ptr @{{.*}}, ptr @{{.*}}, ptr @{{.*}}, ptr @{{.*}}]
+// CHECK: @.offload_sizes = private unnamed_addr constant [12 x i64] [i64 0, i64 48, i64 8, i64 0, i64 0, i64 48, i64 8, i64 0, i64 0, i64 24, i64 8, i64 4]
+// CHECK: @.offload_maptypes = private unnamed_addr constant [12 x i64] [i64 32, i64 281474976710659, i64 281474976710659, i64 281474976710675, i64 32, i64 1407374883553283, i64 1407374883553283, i64 1407374883553299, i64 32, i64 2533274790395907, i64 2533274790395907, i64 2533274790395923]
+// CHECK: @.offload_mapnames = private constant [12 x ptr] [ptr @{{.*}}, ptr @{{.*}}, ptr @{{.*}}, ptr @{{.*}}, ptr @{{.*}}, ptr @{{.*}}, ptr @{{.*}}, ptr @{{.*}}, ptr @{{.*}}, ptr @{{.*}}, ptr @{{.*}}, ptr @{{.*}}]
-// CHECK: define void @_QQmain()
+// CHECK: define void @main()
// CHECK: %[[SCALAR_ALLOCA:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8 }, i64 1, align 8
// CHECK: %[[FULL_ARR_SIZE5:.*]] = load i64, ptr getelementptr ({ ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr @[[FULL_ARR_GLOB]], i32 0, i32 7, i64 0, i32 1), align 4
// CHECK: %[[FULL_ARR_SIZE4:.*]] = sub i64 %[[FULL_ARR_SIZE5]], 1
@@ -79,67 +79,77 @@ module attributes {omp.is_target_device = false, omp.target_triples = ["amdgcn-a
// CHECK: %[[ARR_SECT_SIZE2:.*]] = add i64 %[[ARR_SECT_SIZE3]], 1
// CHECK: %[[ARR_SECT_SIZE1:.*]] = mul i64 1, %[[ARR_SECT_SIZE2]]
// CHECK: %[[ARR_SECT_SIZE:.*]] = mul i64 %[[ARR_SECT_SIZE1]], 4
-// CHECK: %[[LFULL_ARR:.*]] = load ptr, ptr @_QFEfull_arr, align 8
+// CHECK: %[[LFULL_ARR:.*]] = load ptr, ptr @full_arr, align 8
// CHECK: %[[FULL_ARR_PTR:.*]] = getelementptr inbounds float, ptr %[[LFULL_ARR]], i64 0
// CHECK: %[[ARR_SECT_OFFSET1:.*]] = mul i64 %[[ARR_SECT_OFFSET2]], 1
-// CHECK: %[[LARR_SECT:.*]] = load ptr, ptr @_QFEsect_arr, align 8
+// CHECK: %[[LARR_SECT:.*]] = load ptr, ptr @sect_arr, align 8
// CHECK: %[[ARR_SECT_PTR:.*]] = getelementptr inbounds i32, ptr %[[LARR_SECT]], i64 %[[ARR_SECT_OFFSET1]]
// CHECK: %[[SCALAR_PTR_LOAD:.*]] = load ptr, ptr %[[SCALAR_BASE]], align 8
-// CHECK: %[[FULL_ARR_DESC_SIZE:.*]] = sdiv exact i64 sub (i64 ptrtoint (ptr getelementptr ({ ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr @_QFEfull_arr, i32 1) to i64), i64 ptrtoint (ptr @_QFEfull_arr to i64)), ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64)
-// CHECK: %[[ARR_SECT_DESC_SIZE:.*]] = sdiv exact i64 sub (i64 ptrtoint (ptr getelementptr ({ ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr @_QFEsect_arr, i32 1) to i64), i64 ptrtoint (ptr @_QFEsect_arr to i64)), ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64)
+// CHECK: %[[FULL_ARR_DESC_SIZE:.*]] = sdiv exact i64 sub (i64 ptrtoint (ptr getelementptr ({ ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr @full_arr, i32 1) to i64), i64 ptrtoint (ptr @full_arr to i64)), ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64)
+// CHECK: %[[ARR_SECT_DESC_SIZE:.*]] = sdiv exact i64 sub (i64 ptrtoint (ptr getelementptr ({ ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr @sect_arr, i32 1) to i64), i64 ptrtoint (ptr @sect_arr to i64)), ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64)
// CHECK: %[[SCALAR_DESC_SZ4:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8 }, ptr %[[SCALAR_ALLOCA]], i32 1
// CHECK: %[[SCALAR_DESC_SZ3:.*]] = ptrtoint ptr %[[SCALAR_DESC_SZ4]] to i64
// CHECK: %[[SCALAR_DESC_SZ2:.*]] = ptrtoint ptr %[[SCALAR_ALLOCA]] to i64
// CHECK: %[[SCALAR_DESC_SZ1:.*]] = sub i64 %[[SCALAR_DESC_SZ3]], %[[SCALAR_DESC_SZ2]]
// CHECK: %[[SCALAR_DESC_SZ:.*]] = sdiv exact i64 %[[SCALAR_DESC_SZ1]], ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64)
-// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_baseptrs, i32 0, i32 0
-// CHECK: store ptr @_QFEfull_arr, ptr %[[OFFLOADBASEPTRS]], align 8
-// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_ptrs, i32 0, i32 0
-// CHECK: store ptr @_QFEfull_arr, ptr %[[OFFLOADPTRS]], align 8
-
-// CHECK: %[[OFFLOADSIZES:.*]] = getelementptr inbounds [9 x i64], ptr %.offload_sizes, i32 0, i32 0
+// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_baseptrs, i32 0, i32 0
+// CHECK: store ptr @full_arr, ptr %[[OFFLOADBASEPTRS]], align 8
+// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_ptrs, i32 0, i32 0
+// CHECK: store ptr @full_arr, ptr %[[OFFLOADPTRS]], align 8
+// CHECK: %[[OFFLOADSIZES:.*]] = getelementptr inbounds [12 x i64], ptr %.offload_sizes, i32 0, i32 0
// CHECK: store i64 %[[FULL_ARR_DESC_SIZE]], ptr %[[OFFLOADSIZES]], align 8
-
-// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_baseptrs, i32 0, i32 1
-// CHECK: store ptr @_QFEfull_arr, ptr %[[OFFLOADBASEPTRS]], align 8
-// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_ptrs, i32 0, i32 1
-// CHECK: store ptr @_QFEfull_arr, ptr %[[OFFLOADPTRS]], align 8
-// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_baseptrs, i32 0, i32 2
-// CHECK: store ptr @_QFEfull_arr, ptr %[[OFFLOADBASEPTRS]], align 8
-// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_ptrs, i32 0, i32 2
+// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_baseptrs, i32 0, i32 1
+// CHECK: store ptr @full_arr, ptr %[[OFFLOADBASEPTRS]], align 8
+// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_ptrs, i32 0, i32 1
+// CHECK: store ptr @full_arr, ptr %[[OFFLOADPTRS]], align 8
+// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_baseptrs, i32 0, i32 2
+// CHECK: store ptr @full_arr, ptr %[[OFFLOADBASEPTRS]], align 8
+// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_ptrs, i32 0, i32 2
+// CHECK: store ptr @full_arr, ptr %[[OFFLOADPTRS]], align 8
+// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_baseptrs, i32 0, i32 3
+// CHECK: store ptr @full_arr, ptr %[[OFFLOADBASEPTRS]], align 8
+// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_ptrs, i32 0, i32 3
// CHECK: store ptr %[[FULL_ARR_PTR]], ptr %[[OFFLOADPTRS]], align 8
-// CHECK: %[[OFFLOADSIZES:.*]] = getelementptr inbounds [9 x i64], ptr %.offload_sizes, i32 0, i32 2
+// CHECK: %[[OFFLOADSIZES:.*]] = getelementptr inbounds [12 x i64], ptr %.offload_sizes, i32 0, i32 3
// CHECK: store i64 %[[FULL_ARR_SIZE]], ptr %[[OFFLOADSIZES]], align 8
-// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_baseptrs, i32 0, i32 3
-// CHECK: store ptr @_QFEsect_arr, ptr %[[OFFLOADBASEPTRS]], align 8
-// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_ptrs, i32 0, i32 3
-// CHECK: store ptr @_QFEsect_arr, ptr %[[OFFLOADPTRS]], align 8
-// CHECK: %[[OFFLOADSIZES:.*]] = getelementptr inbounds [9 x i64], ptr %.offload_sizes, i32 0, i32 3
+// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_baseptrs, i32 0, i32 4
+// CHECK: store ptr @sect_arr, ptr %[[OFFLOADBASEPTRS]], align 8
+// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_ptrs, i32 0, i32 4
+// CHECK: store ptr @sect_arr, ptr %[[OFFLOADPTRS]], align 8
+// CHECK: %[[OFFLOADSIZES:.*]] = getelementptr inbounds [12 x i64], ptr %.offload_sizes, i32 0, i32 4
// CHECK: store i64 %[[ARR_SECT_DESC_SIZE]], ptr %[[OFFLOADSIZES]], align 8
-// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_baseptrs, i32 0, i32 4
-// CHECK: store ptr @_QFEsect_arr, ptr %[[OFFLOADBASEPTRS]], align 8
-// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_ptrs, i32 0, i32 4
-// CHECK: store ptr @_QFEsect_arr, ptr %[[OFFLOADPTRS]], align 8
-// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_baseptrs, i32 0, i32 5
-// CHECK: store ptr @_QFEsect_arr, ptr %[[OFFLOADBASEPTRS]], align 8
-// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_ptrs, i32 0, i32 5
+// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_baseptrs, i32 0, i32 5
+// CHECK: store ptr @sect_arr, ptr %[[OFFLOADBASEPTRS]], align 8
+// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_ptrs, i32 0, i32 5
+// CHECK: store ptr @sect_arr, ptr %[[OFFLOADPTRS]], align 8
+// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_baseptrs, i32 0, i32 6
+// CHECK: store ptr @sect_arr, ptr %[[OFFLOADBASEPTRS]], align 8
+// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_ptrs, i32 0, i32 6
+// CHECK: store ptr @sect_arr, ptr %[[OFFLOADPTRS]], align 8
+// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_baseptrs, i32 0, i32 7
+// CHECK: store ptr @sect_arr, ptr %[[OFFLOADBASEPTRS]], align 8
+// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_ptrs, i32 0, i32 7
// CHECK: store ptr %[[ARR_SECT_PTR]], ptr %[[OFFLOADPTRS]], align 8
-// CHECK: %[[OFFLOADSIZES:.*]] = getelementptr inbounds [9 x i64], ptr %.offload_sizes, i32 0, i32 5
+// CHECK: %[[OFFLOADSIZES:.*]] = getelementptr inbounds [12 x i64], ptr %.offload_sizes, i32 0, i32 7
// CHECK: store i64 %[[ARR_SECT_SIZE]], ptr %[[OFFLOADSIZES]], align 8
-// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_baseptrs, i32 0, i32 6
+// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_baseptrs, i32 0, i32 8
// CHECK: store ptr %[[SCALAR_ALLOCA]], ptr %[[OFFLOADBASEPTRS]], align 8
-// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_ptrs, i32 0, i32 6
+// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_ptrs, i32 0, i32 8
// CHECK: store ptr %[[SCALAR_ALLOCA]], ptr %[[OFFLOADPTRS]], align 8
-// CHECK: %[[OFFLOADSIZES:.*]] = getelementptr inbounds [9 x i64], ptr %.offload_sizes, i32 0, i32 6
+// CHECK: %[[OFFLOADSIZES:.*]] = getelementptr inbounds [12 x i64], ptr %.offload_sizes, i32 0, i32 8
// CHECK: store i64 %[[SCALAR_DESC_SZ]], ptr %[[OFFLOADSIZES]], align 8
-// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_baseptrs, i32 0, i32 7
+// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_baseptrs, i32 0, i32 9
// CHECK: store ptr %[[SCALAR_ALLOCA]], ptr %[[OFFLOADBASEPTRS]], align 8
-// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_ptrs, i32 0, i32 7
+// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_ptrs, i32 0, i32 9
// CHECK: store ptr %[[SCALAR_ALLOCA]], ptr %[[OFFLOADPTRS]], align 8
-// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_baseptrs, i32 0, i32 8
+// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_baseptrs, i32 0, i32 10
// CHECK: store ptr %[[SCALAR_ALLOCA]], ptr %[[OFFLOADBASEPTRS]], align 8
-// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [9 x ptr], ptr %.offload_ptrs, i32 0, i32 8
+// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_ptrs, i32 0, i32 10
+// CHECK: store ptr %[[SCALAR_BASE]], ptr %[[OFFLOADPTRS]], align 8
+// CHECK: %[[OFFLOADBASEPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_baseptrs, i32 0, i32 11
+// CHECK: store ptr %[[SCALAR_BASE]], ptr %[[OFFLOADBASEPTRS]], align 8
+// CHECK: %[[OFFLOADPTRS:.*]] = getelementptr inbounds [12 x ptr], ptr %.offload_ptrs, i32 0, i32 11
// CHECK: store ptr %[[SCALAR_PTR_LOAD]], ptr %[[OFFLOADPTRS]], align 8
>From 2a5db632ea848ed0e8541fc0c07ea4bfaa6a5761 Mon Sep 17 00:00:00 2001
From: agozillon <Andrew.Gozillon at amd.com>
Date: Fri, 4 Oct 2024 13:09:46 -0500
Subject: [PATCH 3/3] [Flang][OpenMP] Derived type explicit allocatable member
mapping
This PR is one of 3 in a PR stack, this is the primary change set which seeks
to extend the current derived type explicit member mapping support to
handle descriptor member mapping at arbitrary levels of nesting. The PR
stack seems to do this reasonably (from testing so far) but as you can
create quite complex mappings with derived types (in particular when adding
allocatable derived types or arrays of allocatable derived types) I imagine
there will be hiccups, which I am more than happy to address. There will
also be further extensions to this work to handle the implicit auto-magical
mapping of descriptor members in derived types and a few other changes
planned for the future (with some ideas on optimizing things).
The changes in this PR primarily occur in the OpenMP lowering and
the OMPMapInfoFinalization pass.
In the OpenMP lowering several utility functions were added or extended
to support the generation of appropriate intermediate member mappings
which are currently required when the parent (or multiple parents) of a
mapped member are descriptor types. We need to map the entirety of
these types or do a "deep copy" for lack of a better term, where we map
both the base address and the descriptor as without the copying of both
of these we lack the information in the case of the descriptor to access the
member or attach the pointers data to the pointer and in the latter case we
require the base address to map the chunk of data. Currently we do not
segment descriptor based derived types as we do with regular
non-descriptor derived types, we effectively map their entirety in all
cases at the moment, I hope to address this at some point in the future as
it adds a fair bit of a performance penalty to having nestings of allocatable
derived types as an example. The process of mapping all intermediate
descriptor members in a members path only occurs if a member has
an allocatable or object parent in its symbol path or the member itself
is a member or allocatable. This occurs in the
createParentSymAndGenIntermediateMaps function, which will also
generate the appropriate address for the allocatable member
within the derived type to use as a the varPtr field of the map (for
intermediate allocatable maps and final allocatable mappings). In
this case it's necessary as we can't utilise the usual Fortran::lower
functionality such as gatherDataOperandAddrAndBounds without
causing issues later in the lowering due to extra allocas being spawned
which seem to affect the pointer attachment (at least this is my
current assumption, it results in memory access errors on the device
due to incorrect map information generation). This is similar
to why we do not use the MLIR value generated for this and utilise
the original symbol provided when mapping descriptor types external
to derived types. Hopefully this can be rectified in the future so this
function can be simplified and more closely aligned to the other type
mappings. We also make use of fir::CoordinateOp as opposed to the
HLFIR version as the HLFIR version doesn't support the appropriate
lowering to FIR necessary at the moment, we also cannot use a
single CoordinateOp (similarly to a single GEP) as when we index
through a descriptor operation (BoxType) we encounter issues later
in the lowering, however in either case we need access to intermediate
descriptors so individual CoordinateOp's aid this (although, being
able to compress them into a smaller amount of CoordinateOp's may
simplify the IR and perhaps result in a better end product, something
to consider for the future).
The other large change area was in the OMPMapInfoFinalization pass,
where the pass had to be extended to support the expansion of box
types (or multiple nestings of box types) within derived types, or box
type derived types. This requires expanding each BoxType mapping
from one into two maps and then modifying all of the existing
member indices of the overarching parent mapping to account for
the addition of these new members alongside adjusting the existing
member indices to support the addition of these new maps which
extend the original member indices (as a base address of a box type
is currently considered a member of the box type at a position of
0 as when lowered to LLVM-IR it's a pointer contained at this position
in the descriptor type, however, this means extending mapped children
of this expanded descriptor type to additionally incorporate the new
member index in the correct location in its own index list). I believe
there is a reasonable amount of comments that should aid in
understanding this better, alongside the test alterations for the pass.
A subset of the changes were also aimed at making some of the utilities
for packing and unpacking the DenseIntElementsAttr
containing the member indices shareable across the lowering and
OMPMapInfoFinalization, this required moving some functions to the
Lower/Support/Utils.h header, and transforming the lowering structure
containing the member index data into something more similar to the
version used in OMPMapInfoFinalization. There we also some other
attempts at tidying things up in relation to the member index data
generation in the lowering, some of which required creating a logical
operator for the OpenMP ID class so it can be utilised as a map key
(it simply utilises the symbol address for the moment as ordering
isn't particularly important).
Otherwise I have added a set of new tests encompassing some of
the mappings currently supported by this PR (unfortunately as
you can have arbitrary nestings of all shapes and types it's not
very feasible to cover them all).
---
.../flang/Optimizer/Builder/FIRBuilder.h | 5 +
flang/lib/Lower/OpenMP/ClauseProcessor.cpp | 62 ++-
flang/lib/Lower/OpenMP/ClauseProcessor.h | 3 +-
flang/lib/Lower/OpenMP/Clauses.h | 11 +
flang/lib/Lower/OpenMP/OpenMP.cpp | 4 +-
flang/lib/Lower/OpenMP/Utils.cpp | 491 +++++++++++++-----
flang/lib/Lower/OpenMP/Utils.h | 97 +++-
flang/lib/Optimizer/Builder/FIRBuilder.cpp | 20 +
.../Optimizer/OpenMP/MapInfoFinalization.cpp | 437 +++++++++++-----
.../OpenMP/MapsForPrivatizedSymbols.cpp | 2 +-
.../Fir/convert-to-llvm-openmp-and-fir.fir | 166 +++++-
.../OpenMP/map-types-and-sizes.f90 | 471 ++++++++++++++++-
.../Lower/OpenMP/allocatable-array-bounds.f90 | 6 +-
flang/test/Lower/OpenMP/allocatable-map.f90 | 2 +-
flang/test/Lower/OpenMP/array-bounds.f90 | 2 +-
.../OpenMP/declare-target-link-tarop-cap.f90 | 4 +-
.../OpenMP/derived-type-allocatable-map.f90 | 161 ++++++
flang/test/Lower/OpenMP/derived-type-map.f90 | 10 +-
flang/test/Lower/OpenMP/target.f90 | 4 +-
.../Transforms/omp-map-info-finalization.fir | 315 +++++++++--
20 files changed, 1877 insertions(+), 396 deletions(-)
create mode 100644 flang/test/Lower/OpenMP/derived-type-allocatable-map.f90
diff --git a/flang/include/flang/Optimizer/Builder/FIRBuilder.h b/flang/include/flang/Optimizer/Builder/FIRBuilder.h
index 09f7b892f1ecbe..b772c523caba49 100644
--- a/flang/include/flang/Optimizer/Builder/FIRBuilder.h
+++ b/flang/include/flang/Optimizer/Builder/FIRBuilder.h
@@ -215,6 +215,11 @@ class FirOpBuilder : public mlir::OpBuilder, public mlir::OpBuilder::Listener {
llvm::ArrayRef<mlir::Value> lenParams,
bool asTarget = false);
+ /// Create a two dimensional ArrayAttr containing integer data as
+ /// IntegerAttrs, effectively: ArrayAttr<ArrayAttr<IntegerAttr>>>.
+ mlir::ArrayAttr create2DI64ArrayAttr(
+ llvm::SmallVectorImpl<llvm::SmallVector<int64_t>> &intData);
+
/// Create a temporary using `fir.alloca`. This function does not hoist.
/// It is the callers responsibility to set the insertion point if
/// hoisting is required.
diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
index e768c1cbc0784a..aea67fc165b5ba 100644
--- a/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
+++ b/flang/lib/Lower/OpenMP/ClauseProcessor.cpp
@@ -894,14 +894,15 @@ void ClauseProcessor::processMapObjects(
lower::StatementContext &stmtCtx, mlir::Location clauseLocation,
const omp::ObjectList &objects,
llvm::omp::OpenMPOffloadMappingFlags mapTypeBits,
- std::map<const semantics::Symbol *,
- llvm::SmallVector<OmpMapMemberIndicesData>> &parentMemberIndices,
+ std::map<Object, OmpMapParentAndMemberData> &parentMemberIndices,
llvm::SmallVectorImpl<mlir::Value> &mapVars,
llvm::SmallVectorImpl<const semantics::Symbol *> &mapSyms) const {
fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
+
for (const omp::Object &object : objects) {
llvm::SmallVector<mlir::Value> bounds;
std::stringstream asFortran;
+ std::optional<omp::Object> parentObj;
lower::AddrAndBoundsInfo info =
lower::gatherDataOperandAddrAndBounds<mlir::omp::MapBoundsOp,
@@ -910,24 +911,43 @@ void ClauseProcessor::processMapObjects(
object.ref(), clauseLocation, asFortran, bounds,
treatIndexAsSection);
+ mlir::Value baseOp = info.rawInput;
+ if (object.sym()->owner().IsDerivedType()) {
+ omp::ObjectList objectList = gatherObjectsOf(object, semaCtx);
+ assert(!objectList.empty() &&
+ "could not find parent objects of derived type member");
+ parentObj = objectList[0];
+ parentMemberIndices.emplace(parentObj.value(),
+ OmpMapParentAndMemberData{});
+
+ if (isMemberOrParentAllocatableOrPointer(object, semaCtx)) {
+ llvm::SmallVector<int64_t> indices;
+ generateMemberPlacementIndices(object, indices, semaCtx);
+ baseOp = createParentSymAndGenIntermediateMaps(
+ clauseLocation, converter, semaCtx, stmtCtx, objectList, indices,
+ parentMemberIndices[parentObj.value()], asFortran.str(),
+ mapTypeBits);
+ }
+ }
+
// Explicit map captures are captured ByRef by default,
// optimisation passes may alter this to ByCopy or other capture
// types to optimise
- mlir::Value baseOp = info.rawInput;
auto location = mlir::NameLoc::get(
mlir::StringAttr::get(firOpBuilder.getContext(), asFortran.str()),
baseOp.getLoc());
mlir::omp::MapInfoOp mapOp = createMapInfoOp(
firOpBuilder, location, baseOp,
/*varPtrPtr=*/mlir::Value{}, asFortran.str(), bounds,
- /*members=*/{}, /*membersIndex=*/mlir::DenseIntElementsAttr{},
+ /*members=*/{}, /*membersIndex=*/mlir::ArrayAttr{},
static_cast<
std::underlying_type_t<llvm::omp::OpenMPOffloadMappingFlags>>(
mapTypeBits),
mlir::omp::VariableCaptureKind::ByRef, baseOp.getType());
- if (object.sym()->owner().IsDerivedType()) {
- addChildIndexAndMapToParent(object, parentMemberIndices, mapOp, semaCtx);
+ if (parentObj.has_value()) {
+ parentMemberIndices[parentObj.value()].addChildIndexAndMapToParent(
+ object, mapOp, semaCtx);
} else {
mapVars.push_back(mapOp);
mapSyms.push_back(object.sym());
@@ -945,9 +965,7 @@ bool ClauseProcessor::processMap(
llvm::SmallVector<const semantics::Symbol *> localMapSyms;
llvm::SmallVectorImpl<const semantics::Symbol *> *ptrMapSyms =
mapSyms ? mapSyms : &localMapSyms;
- std::map<const semantics::Symbol *,
- llvm::SmallVector<OmpMapMemberIndicesData>>
- parentMemberIndices;
+ std::map<Object, OmpMapParentAndMemberData> parentMemberIndices;
auto process = [&](const omp::clause::Map &clause,
const parser::CharBlock &source) {
@@ -1007,17 +1025,15 @@ bool ClauseProcessor::processMap(
};
bool clauseFound = findRepeatableClause<omp::clause::Map>(process);
- insertChildMapInfoIntoParent(converter, parentMemberIndices, result.mapVars,
- *ptrMapSyms);
+ insertChildMapInfoIntoParent(converter, semaCtx, stmtCtx, parentMemberIndices,
+ result.mapVars, *ptrMapSyms);
return clauseFound;
}
bool ClauseProcessor::processMotionClauses(lower::StatementContext &stmtCtx,
mlir::omp::MapClauseOps &result) {
- std::map<const semantics::Symbol *,
- llvm::SmallVector<OmpMapMemberIndicesData>>
- parentMemberIndices;
+ std::map<Object, OmpMapParentAndMemberData> parentMemberIndices;
llvm::SmallVector<const semantics::Symbol *> mapSymbols;
auto callbackFn = [&](const auto &clause, const parser::CharBlock &source) {
@@ -1044,8 +1060,9 @@ bool ClauseProcessor::processMotionClauses(lower::StatementContext &stmtCtx,
clauseFound =
findRepeatableClause<omp::clause::From>(callbackFn) || clauseFound;
- insertChildMapInfoIntoParent(converter, parentMemberIndices, result.mapVars,
- mapSymbols);
+ insertChildMapInfoIntoParent(converter, semaCtx, stmtCtx, parentMemberIndices,
+ result.mapVars, mapSymbols);
+
return clauseFound;
}
@@ -1107,9 +1124,7 @@ bool ClauseProcessor::processEnter(
bool ClauseProcessor::processUseDeviceAddr(
lower::StatementContext &stmtCtx, mlir::omp::UseDeviceAddrClauseOps &result,
llvm::SmallVectorImpl<const semantics::Symbol *> &useDeviceSyms) const {
- std::map<const semantics::Symbol *,
- llvm::SmallVector<OmpMapMemberIndicesData>>
- parentMemberIndices;
+ std::map<Object, OmpMapParentAndMemberData> parentMemberIndices;
bool clauseFound = findRepeatableClause<omp::clause::UseDeviceAddr>(
[&](const omp::clause::UseDeviceAddr &clause,
const parser::CharBlock &source) {
@@ -1122,7 +1137,7 @@ bool ClauseProcessor::processUseDeviceAddr(
useDeviceSyms);
});
- insertChildMapInfoIntoParent(converter, parentMemberIndices,
+ insertChildMapInfoIntoParent(converter, semaCtx, stmtCtx, parentMemberIndices,
result.useDeviceAddrVars, useDeviceSyms);
return clauseFound;
}
@@ -1130,9 +1145,8 @@ bool ClauseProcessor::processUseDeviceAddr(
bool ClauseProcessor::processUseDevicePtr(
lower::StatementContext &stmtCtx, mlir::omp::UseDevicePtrClauseOps &result,
llvm::SmallVectorImpl<const semantics::Symbol *> &useDeviceSyms) const {
- std::map<const semantics::Symbol *,
- llvm::SmallVector<OmpMapMemberIndicesData>>
- parentMemberIndices;
+ std::map<Object, OmpMapParentAndMemberData> parentMemberIndices;
+
bool clauseFound = findRepeatableClause<omp::clause::UseDevicePtr>(
[&](const omp::clause::UseDevicePtr &clause,
const parser::CharBlock &source) {
@@ -1145,7 +1159,7 @@ bool ClauseProcessor::processUseDevicePtr(
useDeviceSyms);
});
- insertChildMapInfoIntoParent(converter, parentMemberIndices,
+ insertChildMapInfoIntoParent(converter, semaCtx, stmtCtx, parentMemberIndices,
result.useDevicePtrVars, useDeviceSyms);
return clauseFound;
}
diff --git a/flang/lib/Lower/OpenMP/ClauseProcessor.h b/flang/lib/Lower/OpenMP/ClauseProcessor.h
index f34121c70d0b44..cf2fc362a52d8c 100644
--- a/flang/lib/Lower/OpenMP/ClauseProcessor.h
+++ b/flang/lib/Lower/OpenMP/ClauseProcessor.h
@@ -166,8 +166,7 @@ class ClauseProcessor {
lower::StatementContext &stmtCtx, mlir::Location clauseLocation,
const omp::ObjectList &objects,
llvm::omp::OpenMPOffloadMappingFlags mapTypeBits,
- std::map<const semantics::Symbol *,
- llvm::SmallVector<OmpMapMemberIndicesData>> &parentMemberIndices,
+ std::map<Object, OmpMapParentAndMemberData> &parentMemberIndices,
llvm::SmallVectorImpl<mlir::Value> &mapVars,
llvm::SmallVectorImpl<const semantics::Symbol *> &mapSyms) const;
diff --git a/flang/lib/Lower/OpenMP/Clauses.h b/flang/lib/Lower/OpenMP/Clauses.h
index 51180ebfe5745e..64bdf02eaeda86 100644
--- a/flang/lib/Lower/OpenMP/Clauses.h
+++ b/flang/lib/Lower/OpenMP/Clauses.h
@@ -51,6 +51,13 @@ struct IdTyTemplate {
return designator == other.designator;
}
+ // Defining an "ordering" which allows types derived from this to be
+ // utilised in maps and other containers that require comparison
+ // operators for ordering
+ bool operator<(const IdTyTemplate &other) const {
+ return symbol < other.symbol;
+ }
+
operator bool() const { return symbol != nullptr; }
};
@@ -72,6 +79,10 @@ struct ObjectT<Fortran::lower::omp::IdTyTemplate<Fortran::lower::omp::ExprTy>,
Fortran::semantics::Symbol *sym() const { return identity.symbol; }
const std::optional<ExprTy> &ref() const { return identity.designator; }
+ bool operator<(const ObjectT<IdTy, ExprTy> &other) const {
+ return identity < other.identity;
+ }
+
IdTy identity;
};
} // namespace tomp::type
diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index 4f9e2347308aa1..263b8a3d33fdc8 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -1028,7 +1028,7 @@ static void genBodyOfTargetOp(
firOpBuilder, copyVal.getLoc(), copyVal,
/*varPtrPtr=*/mlir::Value{}, name.str(), bounds,
/*members=*/llvm::SmallVector<mlir::Value>{},
- /*membersIndex=*/mlir::DenseIntElementsAttr{},
+ /*membersIndex=*/mlir::ArrayAttr{},
static_cast<
std::underlying_type_t<llvm::omp::OpenMPOffloadMappingFlags>>(
llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT),
@@ -1818,7 +1818,7 @@ genTargetOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
mlir::Value mapOp = createMapInfoOp(
firOpBuilder, location, baseOp, /*varPtrPtr=*/mlir::Value{},
name.str(), bounds, /*members=*/{},
- /*membersIndex=*/mlir::DenseIntElementsAttr{},
+ /*membersIndex=*/mlir::ArrayAttr{},
static_cast<
std::underlying_type_t<llvm::omp::OpenMPOffloadMappingFlags>>(
mapFlag),
diff --git a/flang/lib/Lower/OpenMP/Utils.cpp b/flang/lib/Lower/OpenMP/Utils.cpp
index a09d91540ec222..5a2550bd7fc543 100644
--- a/flang/lib/Lower/OpenMP/Utils.cpp
+++ b/flang/lib/Lower/OpenMP/Utils.cpp
@@ -13,6 +13,8 @@
#include "Utils.h"
#include "Clauses.h"
+#include <DirectivesCommon.h>
+
#include <flang/Lower/AbstractConverter.h>
#include <flang/Lower/ConvertType.h>
#include <flang/Lower/PFTBuilder.h>
@@ -23,8 +25,7 @@
#include <flang/Semantics/tools.h>
#include <llvm/Support/CommandLine.h>
-#include <algorithm>
-#include <numeric>
+#include <iterator>
llvm::cl::opt<bool> treatIndexAsSection(
"openmp-treat-index-as-section",
@@ -119,10 +120,10 @@ void gatherFuncAndVarSyms(
mlir::omp::MapInfoOp
createMapInfoOp(fir::FirOpBuilder &builder, mlir::Location loc,
- mlir::Value baseAddr, mlir::Value varPtrPtr, std::string name,
- llvm::ArrayRef<mlir::Value> bounds,
+ mlir::Value baseAddr, mlir::Value varPtrPtr,
+ llvm::StringRef name, llvm::ArrayRef<mlir::Value> bounds,
llvm::ArrayRef<mlir::Value> members,
- mlir::DenseIntElementsAttr membersIndex, uint64_t mapType,
+ mlir::ArrayAttr membersIndex, uint64_t mapType,
mlir::omp::VariableCaptureKind mapCaptureType, mlir::Type retTy,
bool partialMap) {
if (auto boxTy = llvm::dyn_cast<fir::BaseBoxType>(baseAddr.getType())) {
@@ -145,11 +146,292 @@ createMapInfoOp(fir::FirOpBuilder &builder, mlir::Location loc,
builder.getIntegerAttr(builder.getIntegerType(64, false), mapType),
builder.getAttr<mlir::omp::VariableCaptureKindAttr>(mapCaptureType),
builder.getStringAttr(name), builder.getBoolAttr(partialMap));
-
return op;
}
-static int
+// This function gathers the individual omp::Object's that make up a
+// larger omp::Object symbol.
+//
+// For example, provided the larger symbol: "parent%child%member", this
+// function breaks it up into its constituent components ("parent",
+// "child", "member"), so we can access each individual component and
+// introspect details. Important to note is this function breaks it up from
+// RHS to LHS ("member" to "parent") and then we reverse it so that the
+// returned omp::ObjectList is LHS to RHS, with the "parent" at the
+// beginning.
+omp::ObjectList gatherObjectsOf(omp::Object derivedTypeMember,
+ semantics::SemanticsContext &semaCtx) {
+ omp::ObjectList objList;
+ std::optional<omp::Object> baseObj = derivedTypeMember;
+ while (baseObj.has_value()) {
+ objList.push_back(baseObj.value());
+ baseObj = getBaseObject(baseObj.value(), semaCtx);
+ }
+ return omp::ObjectList{llvm::reverse(objList)};
+}
+
+// This function generates a series of indices from a provided omp::Object,
+// that devolves to an ArrayRef symbol, e.g. "array(2,3,4)", this function
+// would generate a series of indices of "[1][2][3]" for the above example,
+// offsetting by -1 to account for the non-zero fortran indexes.
+//
+// These indices can then be provided to a coordinate operation or other
+// GEP-like operation to access the relevant positional member of the
+// array.
+//
+// It is of note that the function only supports subscript integers currently
+// and not Triplets i.e. Array(1:2:3).
+static void generateArrayIndices(lower::AbstractConverter &converter,
+ fir::FirOpBuilder &firOpBuilder,
+ lower::StatementContext &stmtCtx,
+ mlir::Location clauseLocation,
+ llvm::SmallVectorImpl<mlir::Value> &indices,
+ omp::Object object) {
+ auto maybeRef = evaluate::ExtractDataRef(*object.ref());
+ if (!maybeRef)
+ return;
+
+ auto *arr = std::get_if<evaluate::ArrayRef>(&maybeRef->u);
+ if (!arr)
+ return;
+
+ for (auto v : arr->subscript()) {
+ if (std::holds_alternative<Triplet>(v.u))
+ TODO(clauseLocation, "Triplet indexing in map clause is unsupported");
+
+ auto expr = std::get<Fortran::evaluate::IndirectSubscriptIntegerExpr>(v.u);
+ mlir::Value subscript =
+ fir::getBase(converter.genExprValue(toEvExpr(expr.value()), stmtCtx));
+ mlir::Value one = firOpBuilder.createIntegerConstant(
+ clauseLocation, firOpBuilder.getIndexType(), 1);
+ subscript = firOpBuilder.createConvert(
+ clauseLocation, firOpBuilder.getIndexType(), subscript);
+ indices.push_back(firOpBuilder.create<mlir::arith::SubIOp>(clauseLocation,
+ subscript, one));
+ }
+}
+
+/// When mapping members of derived types, there is a chance that one of the
+/// members along the way to a mapped member is an descriptor. In which case
+/// we have to make sure we generate a map for those along the way otherwise
+/// we will be missing a chunk of data required to actually map the member
+/// type to device. This function effectively generates these maps and the
+/// appropriate data accesses required to generate these maps. It will avoid
+/// creating duplicate maps, as duplicates are just as bad as unmapped
+/// descriptor data in a lot of cases for the runtime (and unnecessary
+/// data movement should be avoided where possible).
+///
+/// As an example for the following mapping:
+///
+/// type :: vertexes
+/// integer(4), allocatable :: vertexx(:)
+/// integer(4), allocatable :: vertexy(:)
+/// end type vertexes
+///
+/// type :: dtype
+/// real(4) :: i
+/// type(vertexes), allocatable :: vertexes(:)
+/// end type dtype
+///
+/// type(dtype), allocatable :: alloca_dtype
+///
+/// !$omp target map(tofrom: alloca_dtype%vertexes(N1)%vertexx)
+///
+/// The below HLFIR/FIR is generated (trimmed for conciseness):
+///
+/// On the first iteration we index into the record type alloca_dtype
+/// to access "vertexes", we then generate a map for this descriptor
+/// alongside bounds to indicate we only need the 1 member, rather than
+/// the whole array block in this case (In theory we could map its
+/// entirety at the cost of data transfer bandwidth).
+///
+/// %13:2 = hlfir.declare ... "alloca_dtype" ...
+/// %39 = fir.load %13#0 : ...
+/// %40 = fir.coordinate_of %39, %c1 : ...
+/// %51 = omp.map.info var_ptr(%40 : ...) map_clauses(to) capture(ByRef) ...
+/// %52 = fir.load %40 : ...
+///
+/// Second iteration generating access to "vertexes(N1) utilising the N1 index
+/// %53 = load N1 ...
+/// %54 = fir.convert %53 : (i32) -> i64
+/// %55 = fir.convert %54 : (i64) -> index
+/// %56 = arith.subi %55, %c1 : index
+/// %57 = fir.coordinate_of %52, %56 : ...
+///
+/// Still in the second iteration we access the allocatable member "vertexx",
+/// we return %58 from the function and provide it to the final and "main"
+/// map of processMap (generated by the record type segment of the below
+/// function), if this were not the final symbol in the list, i.e. we accessed
+/// a member below vertexx, we would have generated the map below as we did in
+/// the first iteration and then continue to generate further coordinates to
+/// access further components as required.
+///
+/// %58 = fir.coordinate_of %57, %c0 : ...
+/// %61 = omp.map.info var_ptr(%58 : ...) map_clauses(to) capture(ByRef) ...
+///
+/// Parent mapping containing prior generated mapped members, generated at
+/// a later step but here to showcase the "end" result
+///
+/// omp.map.info var_ptr(%13#1 : ...) map_clauses(to) capture(ByRef)
+/// members(%50, %61 : [0, 1, 0], [0, 1, 0] : ...
+///
+/// \param objectList - The list of omp::Object symbol data for each parent
+/// to the mapped member (also includes the mapped member), generated via
+/// gatherObjectsOf.
+/// \param indices - List of index data associated with the mapped member
+/// symbol, which identifies the placement of the member in its parent,
+/// this helps generate the appropriate member accesses. These indices
+/// can be generated via generateMemberPlacementIndices.
+/// \param asFortran - A string generated from the mapped variable to be
+/// associated with the main map, generally (but not restricted to)
+/// generated via gatherDataOperandAddrAndBounds or other
+/// DirectiveCommons.hpp utilities.
+/// \param mapTypeBits - The map flags that will be associated with the
+/// generated maps, minus alterations of the TO and FROM bits for the
+/// intermediate components to prevent accidental overwriting on device
+/// write back.
+mlir::Value createParentSymAndGenIntermediateMaps(
+ mlir::Location clauseLocation, lower::AbstractConverter &converter,
+ semantics::SemanticsContext &semaCtx, lower::StatementContext &stmtCtx,
+ omp::ObjectList &objectList, llvm::SmallVectorImpl<int64_t> &indices,
+ OmpMapParentAndMemberData &parentMemberIndices, llvm::StringRef asFortran,
+ llvm::omp::OpenMPOffloadMappingFlags mapTypeBits) {
+ fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
+
+ /// Checks if an omp::Object is an array expression with a subscript, e.g.
+ /// array(1,2).
+ auto isArrayExprWithSubscript = [](omp::Object obj) {
+ if (auto maybeRef = evaluate::ExtractDataRef(*obj.ref())) {
+ evaluate::DataRef ref = *maybeRef;
+ if (auto *arr = std::get_if<evaluate::ArrayRef>(&ref.u))
+ return !arr->subscript().empty();
+ }
+ return false;
+ };
+
+ // Generate the access to the original parent base address.
+ lower::AddrAndBoundsInfo parentBaseAddr = lower::getDataOperandBaseAddr(
+ converter, firOpBuilder, *objectList[0].sym(), clauseLocation);
+ mlir::Value curValue = parentBaseAddr.addr;
+
+ // Iterate over all objects in the objectList, this should consist of all
+ // record types between the parent and the member being mapped (including
+ // the parent). The object list may also contain array objects as well,
+ // this can occur when specifying bounds or a specific element access
+ // within a member map, we skip these.
+ size_t currentIndicesIdx = 0;
+ for (size_t i = 0; i < objectList.size(); ++i) {
+ // If we encounter a sequence type, i.e. an array, we must generate the
+ // correct coordinate operation to index into the array to proceed further,
+ // this is only relevant in cases where we encounter subscripts currently.
+ //
+ // For example in the following case:
+ //
+ // map(tofrom: array_dtype(4)%internal_dtypes(3)%float_elements(4))
+ //
+ // We must generate coordinate operation accesses for each subscript
+ // we encounter.
+ if (fir::SequenceType arrType = mlir::dyn_cast<fir::SequenceType>(
+ fir::unwrapPassByRefType(curValue.getType()))) {
+ if (isArrayExprWithSubscript (objectList[i])) {
+ llvm::SmallVector<mlir::Value> subscriptIndices;
+ generateArrayIndices(converter, firOpBuilder, stmtCtx, clauseLocation,
+ subscriptIndices, objectList[i]);
+ assert(!subscriptIndices.empty() && "missing expected indices for map clause");
+ curValue = firOpBuilder.create<fir::CoordinateOp>(
+ clauseLocation, firOpBuilder.getRefType(arrType.getEleTy()),
+ curValue, subscriptIndices);
+ }
+ }
+
+ // If we encounter a record type, we must access the subsequent member
+ // by indexing into it and creating a coordinate operation to do so, we
+ // utilise the index information generated previously and passed in to
+ // work out the correct member to access and the corresponding member
+ // type.
+ if (fir::RecordType recordType = mlir::dyn_cast<fir::RecordType>(
+ fir::unwrapPassByRefType(curValue.getType()))) {
+ mlir::Value idxConst = firOpBuilder.createIntegerConstant(
+ clauseLocation, firOpBuilder.getIndexType(), indices[currentIndicesIdx]);
+ mlir::Type memberTy =
+ recordType.getTypeList().at(indices[currentIndicesIdx]).second;
+ curValue = firOpBuilder.create<fir::CoordinateOp>(
+ clauseLocation, firOpBuilder.getRefType(memberTy), curValue,
+ idxConst);
+
+ // Skip mapping and the subsequent load if we're the final member or not
+ // a type with a descriptor such as a pointer/allocatable. If we're a
+ // final member, the map will be generated by the processMap call that
+ // invoked this function, and if we're not a type with a descriptor then
+ // we have no need of generating an intermediate map for it, as we only
+ // need to generate a map if a member is a descriptor type (and thus
+ // obscures the members it contains via a pointer in which it's data needs
+ // mapped)
+ if ((currentIndicesIdx == indices.size() - 1) ||
+ !fir::isTypeWithDescriptor(memberTy)) {
+ currentIndicesIdx++;
+ continue;
+ }
+
+ llvm::SmallVector<int64_t> interimIndices(
+ indices.begin(), std::next(indices.begin(), currentIndicesIdx + 1));
+ // Verify we haven't already created a map for this particular member, by
+ // checking the list of members already mapped for the current parent,
+ // stored in the parentMemberIndices structure
+ if (!parentMemberIndices.isDuplicateMemberMapInfo(interimIndices)) {
+ // Generate bounds operations using the standard lowering utility,
+ // unfortunately this currently does a bit more than just generate
+ // bounds and we discard the other bits. May be useful to extend the
+ // utility to just provide bounds in the future.
+ llvm::SmallVector<mlir::Value> interimBounds;
+ if (i + 1 < objectList.size() &&
+ objectList[i + 1].sym()->IsObjectArray()) {
+ std::stringstream interimFortran;
+ Fortran::lower::gatherDataOperandAddrAndBounds<
+ mlir::omp::MapBoundsOp, mlir::omp::MapBoundsType>(
+ converter, converter.getFirOpBuilder(), semaCtx,
+ converter.getFctCtx(), *objectList[i + 1].sym(),
+ objectList[i + 1].ref(), clauseLocation, interimFortran,
+ interimBounds, treatIndexAsSection);
+ }
+
+ // Remove all map TO, FROM and TOFROM bits, from the intermediate
+ // allocatable maps, we simply wish to alloc or release them. It may be
+ // safer to just pass OMP_MAP_NONE as the map type, but we may still
+ // need some of the other map types the mapped member utilises, so for
+ // now it's good to keep an eye on this.
+ llvm::omp::OpenMPOffloadMappingFlags interimMapType = mapTypeBits;
+ interimMapType &= ~llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO;
+ interimMapType &= ~llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_FROM;
+
+ // Create a map for the intermediate member and insert it and it's
+ // indices into the parentMemberIndices list to track it.
+ mlir::omp::MapInfoOp mapOp = createMapInfoOp(
+ firOpBuilder, clauseLocation, curValue,
+ /*varPtrPtr=*/mlir::Value{}, asFortran,
+ /*bounds=*/interimBounds,
+ /*members=*/{},
+ /*membersIndex=*/mlir::ArrayAttr{},
+ static_cast<
+ std::underlying_type_t<llvm::omp::OpenMPOffloadMappingFlags>>(
+ interimMapType),
+ mlir::omp::VariableCaptureKind::ByRef, curValue.getType());
+
+ parentMemberIndices.memberPlacementIndices.push_back(interimIndices);
+ parentMemberIndices.memberMap.push_back(mapOp);
+ }
+
+ // Load the currently accessed member, so we can continue to access
+ // further segments.
+ curValue = firOpBuilder.create<fir::LoadOp>(clauseLocation, curValue);
+ currentIndicesIdx++;
+ }
+ }
+
+ return curValue;
+}
+
+static int64_t
getComponentPlacementInParent(const semantics::Symbol *componentSym) {
const auto *derived = componentSym->owner()
.derivedTypeSpec()
@@ -183,101 +465,66 @@ getComponentObject(std::optional<Object> object,
return getComponentObject(baseObj.value(), semaCtx);
}
-static void
-generateMemberPlacementIndices(const Object &object,
- llvm::SmallVectorImpl<int> &indices,
- semantics::SemanticsContext &semaCtx) {
+void generateMemberPlacementIndices(const Object &object,
+ llvm::SmallVectorImpl<int64_t> &indices,
+ semantics::SemanticsContext &semaCtx) {
+ assert(indices.empty() && "indices vector passed to "
+ "generateMemberPlacementIndices should be empty");
auto compObj = getComponentObject(object, semaCtx);
+
while (compObj) {
- indices.push_back(getComponentPlacementInParent(compObj->sym()));
+ int64_t index = getComponentPlacementInParent(compObj->sym());
+ assert(
+ index >= 0 &&
+ "unexpected index value returned from getComponentPlacementInParent");
+ indices.push_back(index);
compObj =
getComponentObject(getBaseObject(compObj.value(), semaCtx), semaCtx);
}
- indices = llvm::SmallVector<int>{llvm::reverse(indices)};
+ indices = llvm::SmallVector<int64_t>{llvm::reverse(indices)};
}
-void addChildIndexAndMapToParent(
- const omp::Object &object,
- std::map<const semantics::Symbol *,
- llvm::SmallVector<OmpMapMemberIndicesData>> &parentMemberIndices,
- mlir::omp::MapInfoOp &mapOp, semantics::SemanticsContext &semaCtx) {
- std::optional<evaluate::DataRef> dataRef = ExtractDataRef(object.ref());
- assert(dataRef.has_value() &&
- "DataRef could not be extracted during mapping of derived type "
- "cannot proceed");
- const semantics::Symbol *parentSym = &dataRef->GetFirstSymbol();
- assert(parentSym && "Could not find parent symbol during lower of "
- "a component member in OpenMP map clause");
- llvm::SmallVector<int> indices;
+void OmpMapParentAndMemberData::addChildIndexAndMapToParent(
+ const omp::Object &object, mlir::omp::MapInfoOp &mapOp,
+ semantics::SemanticsContext &semaCtx) {
+ llvm::SmallVector<int64_t> indices;
generateMemberPlacementIndices(object, indices, semaCtx);
- parentMemberIndices[parentSym].push_back({indices, mapOp});
+ memberPlacementIndices.push_back(indices);
+ memberMap.push_back(mapOp);
}
-static void calculateShapeAndFillIndices(
- llvm::SmallVectorImpl<int64_t> &shape,
- llvm::SmallVectorImpl<OmpMapMemberIndicesData> &memberPlacementData) {
- shape.push_back(memberPlacementData.size());
- size_t largestIndicesSize =
- std::max_element(memberPlacementData.begin(), memberPlacementData.end(),
- [](auto a, auto b) {
- return a.memberPlacementIndices.size() <
- b.memberPlacementIndices.size();
- })
- ->memberPlacementIndices.size();
- shape.push_back(largestIndicesSize);
-
- // DenseElementsAttr expects a rectangular shape for the data, so all
- // index lists have to be of the same length, this emplaces -1 as filler.
- for (auto &v : memberPlacementData) {
- if (v.memberPlacementIndices.size() < largestIndicesSize) {
- auto *prevEnd = v.memberPlacementIndices.end();
- v.memberPlacementIndices.resize(largestIndicesSize);
- std::fill(prevEnd, v.memberPlacementIndices.end(), -1);
- }
+bool isMemberOrParentAllocatableOrPointer(
+ const Object &object, semantics::SemanticsContext &semaCtx) {
+ if (semantics::IsAllocatableOrObjectPointer(object.sym()))
+ return true;
+
+ auto compObj = getBaseObject(object, semaCtx);
+ while (compObj) {
+ if (semantics::IsAllocatableOrObjectPointer(compObj.value().sym()))
+ return true;
+ compObj = getBaseObject(compObj.value(), semaCtx);
}
-}
-static mlir::DenseIntElementsAttr createDenseElementsAttrFromIndices(
- llvm::SmallVectorImpl<OmpMapMemberIndicesData> &memberPlacementData,
- fir::FirOpBuilder &builder) {
- llvm::SmallVector<int64_t> shape;
- calculateShapeAndFillIndices(shape, memberPlacementData);
-
- llvm::SmallVector<int> indicesFlattened =
- std::accumulate(memberPlacementData.begin(), memberPlacementData.end(),
- llvm::SmallVector<int>(),
- [](llvm::SmallVector<int> &x, OmpMapMemberIndicesData y) {
- x.insert(x.end(), y.memberPlacementIndices.begin(),
- y.memberPlacementIndices.end());
- return x;
- });
-
- return mlir::DenseIntElementsAttr::get(
- mlir::VectorType::get(shape,
- mlir::IntegerType::get(builder.getContext(), 32)),
- indicesFlattened);
+ return false;
}
void insertChildMapInfoIntoParent(
- lower::AbstractConverter &converter,
- std::map<const semantics::Symbol *,
- llvm::SmallVector<OmpMapMemberIndicesData>> &parentMemberIndices,
+ lower::AbstractConverter &converter, semantics::SemanticsContext &semaCtx,
+ lower::StatementContext &stmtCtx,
+ std::map<Object, OmpMapParentAndMemberData> &parentMemberIndices,
llvm::SmallVectorImpl<mlir::Value> &mapOperands,
llvm::SmallVectorImpl<const semantics::Symbol *> &mapSyms) {
+ fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
for (auto indices : parentMemberIndices) {
- bool parentExists = false;
- size_t parentIdx;
- for (parentIdx = 0; parentIdx < mapSyms.size(); ++parentIdx) {
- if (mapSyms[parentIdx] == indices.first) {
- parentExists = true;
- break;
- }
- }
-
- if (parentExists) {
+ auto *parentIter =
+ llvm::find_if(mapSyms, [&indices](const semantics::Symbol *v) {
+ return v == indices.first.sym();
+ });
+ if (parentIter != mapSyms.end()) {
auto mapOp = llvm::cast<mlir::omp::MapInfoOp>(
- mapOperands[parentIdx].getDefiningOp());
+ mapOperands[std::distance(mapSyms.begin(), parentIter)]
+ .getDefiningOp());
// NOTE: To maintain appropriate SSA ordering, we move the parent map
// which will now have references to its children after the last
@@ -285,71 +532,55 @@ void insertChildMapInfoIntoParent(
// has defined a series of parent and children maps where the parent
// precedes the children. An alternative, may be to do
// delayed generation of map info operations from the clauses and
- // organize them first before generation.
- mapOp->moveAfter(indices.second.back().memberMap);
+ // organize them first before generation. Or to use the
+ // topologicalSort utility which will enforce a stronger SSA
+ // dominance ordering at the cost of efficiency/time.
+ mapOp->moveAfter(indices.second.memberMap.back());
- for (auto memberIndicesData : indices.second)
- mapOp.getMembersMutable().append(
- memberIndicesData.memberMap.getResult());
+ for (mlir::omp::MapInfoOp memberMap : indices.second.memberMap)
+ mapOp.getMembersMutable().append(memberMap.getResult());
- mapOp.setMembersIndexAttr(createDenseElementsAttrFromIndices(
- indices.second, converter.getFirOpBuilder()));
+ mapOp.setMembersIndexAttr(firOpBuilder.create2DI64ArrayAttr(
+ indices.second.memberPlacementIndices));
} else {
// NOTE: We take the map type of the first child, this may not
// be the correct thing to do, however, we shall see. For the moment
// it allows this to work with enter and exit without causing MLIR
// verification issues. The more appropriate thing may be to take
// the "main" map type clause from the directive being used.
- uint64_t mapType = indices.second[0].memberMap.getMapType().value_or(0);
-
- // create parent to emplace and bind members
- mlir::Value origSymbol = converter.getSymbolAddress(*indices.first);
+ uint64_t mapType = indices.second.memberMap[0].getMapType().value_or(0);
llvm::SmallVector<mlir::Value> members;
- for (OmpMapMemberIndicesData memberIndicesData : indices.second)
- members.push_back((mlir::Value)memberIndicesData.memberMap);
-
- mlir::Value mapOp = createMapInfoOp(
- converter.getFirOpBuilder(), origSymbol.getLoc(), origSymbol,
- /*varPtrPtr=*/mlir::Value(), indices.first->name().ToString(),
- /*bounds=*/{}, members,
- createDenseElementsAttrFromIndices(indices.second,
- converter.getFirOpBuilder()),
- mapType, mlir::omp::VariableCaptureKind::ByRef, origSymbol.getType(),
+ members.reserve(indices.second.memberMap.size());
+ for (mlir::omp::MapInfoOp memberMap : indices.second.memberMap)
+ members.push_back(memberMap.getResult());
+
+ // Create parent to emplace and bind members
+ llvm::SmallVector<mlir::Value> bounds;
+ std::stringstream asFortran;
+ lower::AddrAndBoundsInfo info =
+ lower::gatherDataOperandAddrAndBounds<mlir::omp::MapBoundsOp,
+ mlir::omp::MapBoundsType>(
+ converter, firOpBuilder, semaCtx, converter.getFctCtx(),
+ *indices.first.sym(), indices.first.ref(),
+ converter.getCurrentLocation(), asFortran, bounds,
+ treatIndexAsSection);
+
+ mlir::omp::MapInfoOp mapOp = createMapInfoOp(
+ firOpBuilder, info.rawInput.getLoc(), info.rawInput,
+ /*varPtrPtr=*/mlir::Value(), asFortran.str(), bounds, members,
+ firOpBuilder.create2DI64ArrayAttr(
+ indices.second.memberPlacementIndices),
+ mapType, mlir::omp::VariableCaptureKind::ByRef,
+ info.rawInput.getType(),
/*partialMap=*/true);
mapOperands.push_back(mapOp);
- mapSyms.push_back(indices.first);
+ mapSyms.push_back(indices.first.sym());
}
}
}
-semantics::Symbol *getOmpObjectSymbol(const parser::OmpObject &ompObject) {
- semantics::Symbol *sym = nullptr;
- Fortran::common::visit(
- common::visitors{
- [&](const parser::Designator &designator) {
- if (auto *arrayEle =
- parser::Unwrap<parser::ArrayElement>(designator)) {
- // Use getLastName to retrieve the arrays symbol, this will
- // provide the farthest right symbol (the last) in a designator,
- // i.e. providing something like the following:
- // "dtype1%dtype2%array[2:10]", will result in "array"
- sym = GetLastName(arrayEle->base).symbol;
- } else if (auto *structComp =
- parser::Unwrap<parser::StructureComponent>(
- designator)) {
- sym = structComp->component.symbol;
- } else if (const parser::Name *name =
- semantics::getDesignatorNameIfDataRef(designator)) {
- sym = name->symbol;
- }
- },
- [&](const parser::Name &name) { sym = name.symbol; }},
- ompObject.u);
- return sym;
-}
-
void lastprivateModifierNotSupported(const omp::clause::Lastprivate &lastp,
mlir::Location loc) {
using Lastprivate = omp::clause::Lastprivate;
diff --git a/flang/lib/Lower/OpenMP/Utils.h b/flang/lib/Lower/OpenMP/Utils.h
index 4a569cd64355d3..f2e378443e5f29 100644
--- a/flang/lib/Lower/OpenMP/Utils.h
+++ b/flang/lib/Lower/OpenMP/Utils.h
@@ -14,6 +14,7 @@
#include "mlir/IR/Location.h"
#include "mlir/IR/Value.h"
#include "llvm/Support/CommandLine.h"
+#include <cstdint>
extern llvm::cl::opt<bool> treatIndexAsSection;
extern llvm::cl::opt<bool> enableDelayedPrivatization;
@@ -34,6 +35,7 @@ struct OmpObjectList;
} // namespace parser
namespace lower {
+class StatementContext;
namespace pft {
struct Evaluation;
}
@@ -49,37 +51,98 @@ using DeclareTargetCapturePair =
// and index data when lowering OpenMP map clauses. Keeps track of the
// placement of the component in the derived type hierarchy it rests within,
// alongside the generated mlir::omp::MapInfoOp for the mapped component.
-struct OmpMapMemberIndicesData {
+//
+// As an example of what the contents of this data structure may be like,
+// when provided the following derived type and map of that type:
+//
+// type :: bottom_layer
+// real(8) :: i2
+// real(4) :: array_i2(10)
+// real(4) :: array_j2(10)
+// end type bottom_layer
+//
+// type :: top_layer
+// real(4) :: i
+// integer(4) :: array_i(10)
+// real(4) :: j
+// type(bottom_layer) :: nested
+// integer, allocatable :: array_j(:)
+// integer(4) :: k
+// end type top_layer
+//
+// type(top_layer) :: top_dtype
+//
+// map(tofrom: top_dtype%nested%i2, top_dtype%k, top_dtype%nested%array_i2)
+//
+// We would end up with an OmpMapParentAndMemberData populated like below:
+//
+// memberPlacementIndices:
+// Vector 1: 3, 0
+// Vector 2: 5
+// Vector 3: 3, 1
+//
+// memberMap:
+// Entry 1: omp.map.info for "top_dtype%nested%i2"
+// Entry 2: omp.map.info for "top_dtype%k"
+// Entry 3: omp.map.info for "top_dtype%nested%array_i2"
+//
+// And this OmpMapParentAndMemberData would be accessed via the parent
+// symbol for top_dtype. Other parent derived type instances that have
+// members mapped would have there own OmpMapParentAndMemberData entry
+// accessed via their own symbol.
+struct OmpMapParentAndMemberData {
// The indices representing the component members placement in its derived
// type parents hierarchy.
- llvm::SmallVector<int> memberPlacementIndices;
+ llvm::SmallVector<llvm::SmallVector<int64_t>> memberPlacementIndices;
// Placement of the member in the member vector.
- mlir::omp::MapInfoOp memberMap;
+ llvm::SmallVector<mlir::omp::MapInfoOp> memberMap;
+
+ bool isDuplicateMemberMapInfo(llvm::SmallVectorImpl<int64_t> &memberIndices) {
+ return llvm::find_if(memberPlacementIndices, [&](auto &memberData) {
+ return llvm::equal(memberIndices, memberData);
+ }) != memberPlacementIndices.end();
+ }
+
+ void addChildIndexAndMapToParent(const omp::Object &object,
+ mlir::omp::MapInfoOp &mapOp,
+ semantics::SemanticsContext &semaCtx);
};
mlir::omp::MapInfoOp
createMapInfoOp(fir::FirOpBuilder &builder, mlir::Location loc,
- mlir::Value baseAddr, mlir::Value varPtrPtr, std::string name,
- mlir::ArrayRef<mlir::Value> bounds,
- mlir::ArrayRef<mlir::Value> members,
- mlir::DenseIntElementsAttr membersIndex, uint64_t mapType,
+ mlir::Value baseAddr, mlir::Value varPtrPtr,
+ llvm::StringRef name, llvm::ArrayRef<mlir::Value> bounds,
+ llvm::ArrayRef<mlir::Value> members,
+ mlir::ArrayAttr membersIndex, uint64_t mapType,
mlir::omp::VariableCaptureKind mapCaptureType, mlir::Type retTy,
bool partialMap = false);
-void addChildIndexAndMapToParent(
- const omp::Object &object,
- std::map<const semantics::Symbol *,
- llvm::SmallVector<OmpMapMemberIndicesData>> &parentMemberIndices,
- mlir::omp::MapInfoOp &mapOp, semantics::SemanticsContext &semaCtx);
-
void insertChildMapInfoIntoParent(
- lower::AbstractConverter &converter,
- std::map<const semantics::Symbol *,
- llvm::SmallVector<OmpMapMemberIndicesData>> &parentMemberIndices,
+ Fortran::lower::AbstractConverter &converter,
+ Fortran::semantics::SemanticsContext &semaCtx,
+ Fortran::lower::StatementContext &stmtCtx,
+ std::map<Object, OmpMapParentAndMemberData> &parentMemberIndices,
llvm::SmallVectorImpl<mlir::Value> &mapOperands,
llvm::SmallVectorImpl<const semantics::Symbol *> &mapSyms);
+void generateMemberPlacementIndices(
+ const Object &object, llvm::SmallVectorImpl<int64_t> &indices,
+ Fortran::semantics::SemanticsContext &semaCtx);
+
+bool isMemberOrParentAllocatableOrPointer(
+ const Object &object, Fortran::semantics::SemanticsContext &semaCtx);
+
+mlir::Value createParentSymAndGenIntermediateMaps(
+ mlir::Location clauseLocation, Fortran::lower::AbstractConverter &converter,
+ semantics::SemanticsContext &semaCtx, lower::StatementContext &stmtCtx,
+ omp::ObjectList &objectList, llvm::SmallVectorImpl<int64_t> &indices,
+ OmpMapParentAndMemberData &parentMemberIndices, llvm::StringRef asFortran,
+ llvm::omp::OpenMPOffloadMappingFlags mapTypeBits);
+
+omp::ObjectList gatherObjectsOf(omp::Object derivedTypeMember,
+ semantics::SemanticsContext &semaCtx);
+
mlir::Type getLoopVarType(lower::AbstractConverter &converter,
std::size_t loopVarTypeSize);
@@ -92,8 +155,6 @@ void gatherFuncAndVarSyms(
int64_t getCollapseValue(const List<Clause> &clauses);
-semantics::Symbol *getOmpObjectSymbol(const parser::OmpObject &ompObject);
-
void genObjectList(const ObjectList &objects,
lower::AbstractConverter &converter,
llvm::SmallVectorImpl<mlir::Value> &operands);
diff --git a/flang/lib/Optimizer/Builder/FIRBuilder.cpp b/flang/lib/Optimizer/Builder/FIRBuilder.cpp
index 8fa695a5c0c2e1..3a39c455015f9f 100644
--- a/flang/lib/Optimizer/Builder/FIRBuilder.cpp
+++ b/flang/lib/Optimizer/Builder/FIRBuilder.cpp
@@ -267,6 +267,26 @@ mlir::Block *fir::FirOpBuilder::getAllocaBlock() {
return getEntryBlock();
}
+static mlir::ArrayAttr makeI64ArrayAttr(llvm::ArrayRef<int64_t> values,
+ mlir::MLIRContext *context) {
+ llvm::SmallVector<mlir::Attribute, 4> attrs;
+ attrs.reserve(values.size());
+ for (auto &v : values)
+ attrs.push_back(mlir::IntegerAttr::get(mlir::IntegerType::get(context, 64),
+ mlir::APInt(64, v)));
+ return mlir::ArrayAttr::get(context, attrs);
+}
+
+mlir::ArrayAttr fir::FirOpBuilder::create2DI64ArrayAttr(
+ llvm::SmallVectorImpl<llvm::SmallVector<int64_t>> &intData) {
+ llvm::SmallVector<mlir::Attribute> arrayAttr;
+ arrayAttr.reserve(intData.size());
+ mlir::MLIRContext *context = getContext();
+ for (auto &v : intData)
+ arrayAttr.push_back(makeI64ArrayAttr(v, context));
+ return mlir::ArrayAttr::get(context, arrayAttr);
+}
+
mlir::Value fir::FirOpBuilder::createTemporaryAlloc(
mlir::Location loc, mlir::Type type, llvm::StringRef name,
mlir::ValueRange lenParams, mlir::ValueRange shape,
diff --git a/flang/lib/Optimizer/OpenMP/MapInfoFinalization.cpp b/flang/lib/Optimizer/OpenMP/MapInfoFinalization.cpp
index 7ebeb51cf3dec7..87f092e69fe43a 100644
--- a/flang/lib/Optimizer/OpenMP/MapInfoFinalization.cpp
+++ b/flang/lib/Optimizer/OpenMP/MapInfoFinalization.cpp
@@ -38,7 +38,10 @@
#include "mlir/Support/LLVM.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/Frontend/OpenMP/OMPConstants.h"
+#include <algorithm>
+#include <cstddef>
#include <iterator>
+#include <numeric>
namespace flangomp {
#define GEN_PASS_DEF_MAPINFOFINALIZATIONPASS
@@ -49,6 +52,12 @@ namespace {
class MapInfoFinalizationPass
: public flangomp::impl::MapInfoFinalizationPassBase<
MapInfoFinalizationPass> {
+ /// Helper class tracking a members parent and its
+ /// placement in the parents member list
+ struct ParentAndPlacement {
+ mlir::omp::MapInfoOp parent;
+ size_t index;
+ };
/// Tracks any intermediate function/subroutine local allocations we
/// generate for the descriptors of box type dummy arguments, so that
@@ -58,21 +67,66 @@ class MapInfoFinalizationPass
/*corresponding local alloca=*/fir::AllocaOp>
localBoxAllocas;
- void genDescriptorMemberMaps(mlir::omp::MapInfoOp op,
- fir::FirOpBuilder &builder,
- mlir::Operation *target) {
- mlir::Location loc = op.getLoc();
- mlir::Value descriptor = op.getVarPtr();
+ /// getMemberUserList gathers all users of a particular MapInfoOp that are
+ /// other MapInfoOp's and places them into the mapMemberUsers list, which
+ /// records the map that the current argument MapInfoOp "op" is part of
+ /// alongside the placement of "op" in the recorded users members list. The
+ /// intent of the generated list is to find all MapInfoOp's that may be
+ /// considered parents of the passed in "op" and in which it shows up in the
+ /// member list, alongside collecting the placement information of "op" in its
+ /// parents member list.
+ void
+ getMemberUserList(mlir::omp::MapInfoOp op,
+ llvm::SmallVectorImpl<ParentAndPlacement> &mapMemberUsers) {
+ for (auto *user : op->getUsers())
+ if (auto map = mlir::dyn_cast_if_present<mlir::omp::MapInfoOp>(user))
+ for (auto [i, mapMember] : llvm::enumerate(map.getMembers()))
+ if (mapMember.getDefiningOp() == op)
+ mapMemberUsers.push_back({map, i});
+ }
+
+ void getAsIntegers(llvm::ArrayRef<mlir::Attribute> values,
+ llvm::SmallVectorImpl<int64_t> &ints) {
+ ints.reserve(values.size());
+ llvm::transform(values, std::back_inserter(ints),
+ [](mlir::Attribute value) {
+ return mlir::cast<mlir::IntegerAttr>(value).getInt();
+ });
+ }
- // If we enter this function, but the mapped type itself is not the
- // descriptor, then it's likely the address of the descriptor so we
- // must retrieve the descriptor SSA.
- if (!fir::isTypeWithDescriptor(op.getVarType())) {
+ /// This function will expand a MapInfoOp's member indices back into a vector
+ /// so that they can be trivially modified as unfortunately the attribute type
+ /// that's used does not have modifiable fields at the moment (generally
+ /// awkward to work with)
+ void getMemberIndicesAsVectors(
+ mlir::omp::MapInfoOp mapInfo,
+ llvm::SmallVectorImpl<llvm::SmallVector<int64_t>> &indices) {
+ indices.reserve(mapInfo.getMembersIndexAttr().getValue().size());
+ llvm::transform(mapInfo.getMembersIndexAttr().getValue(),
+ std::back_inserter(indices), [this](mlir::Attribute value) {
+ auto memberIndex = mlir::cast<mlir::ArrayAttr>(value);
+ llvm::SmallVector<int64_t> indexes;
+ getAsIntegers(memberIndex.getValue(), indexes);
+ return indexes;
+ });
+ }
+
+ /// When provided a MapInfoOp containing a descriptor type that
+ /// we must expand into multiple maps this function will extract
+ /// the value from it and return it, in certain cases we must
+ /// generate a new allocation to store into so that the
+ /// fir::BoxOffsetOp we utilise to access the descriptor datas
+ /// base address can be utilised.
+ mlir::Value getDescriptorFromBoxMap(mlir::omp::MapInfoOp boxMap,
+ fir::FirOpBuilder &builder) {
+ mlir::Value descriptor = boxMap.getVarPtr();
+ if (!fir::isTypeWithDescriptor(boxMap.getVarType()))
if (auto addrOp = mlir::dyn_cast_if_present<fir::BoxAddrOp>(
- op.getVarPtr().getDefiningOp())) {
+ boxMap.getVarPtr().getDefiningOp()))
descriptor = addrOp.getVal();
- }
- }
+
+ if (!mlir::isa<fir::BaseBoxType>(descriptor.getType()))
+ return descriptor;
// The fir::BoxOffsetOp only works with !fir.ref<!fir.box<...>> types, as
// allowing it to access non-reference box operations can cause some
@@ -81,105 +135,188 @@ class MapInfoFinalizationPass
// !fir.ref<!fir.box<...>> to access the data we need to map we must
// perform an alloca and then store to it and retrieve the data from the new
// alloca.
- if (mlir::isa<fir::BaseBoxType>(descriptor.getType())) {
- // If we have already created a local allocation for this BoxType,
- // we must be sure to re-use it so that we end up with the same
- // allocations being utilised for the same descriptor across all map uses,
- // this prevents runtime issues such as not appropriately releasing or
- // deleting all mapped data.
- auto find = localBoxAllocas.find(descriptor.getAsOpaquePointer());
- if (find != localBoxAllocas.end()) {
- builder.create<fir::StoreOp>(loc, descriptor, find->second);
- descriptor = find->second;
- } else {
- mlir::OpBuilder::InsertPoint insPt = builder.saveInsertionPoint();
- mlir::Block *allocaBlock = builder.getAllocaBlock();
- assert(allocaBlock && "No alloca block found for this top level op");
- builder.setInsertionPointToStart(allocaBlock);
- auto alloca = builder.create<fir::AllocaOp>(loc, descriptor.getType());
- builder.restoreInsertionPoint(insPt);
- builder.create<fir::StoreOp>(loc, descriptor, alloca);
- localBoxAllocas[descriptor.getAsOpaquePointer()] = alloca;
- descriptor = alloca;
- }
- }
+ mlir::OpBuilder::InsertPoint insPt = builder.saveInsertionPoint();
+ mlir::Block *allocaBlock = builder.getAllocaBlock();
+ mlir::Location loc = boxMap->getLoc();
+ assert(allocaBlock && "No alloca block found for this top level op");
+ builder.setInsertionPointToStart(allocaBlock);
+ auto alloca = builder.create<fir::AllocaOp>(loc, descriptor.getType());
+ builder.restoreInsertionPoint(insPt);
+ builder.create<fir::StoreOp>(loc, descriptor, alloca);
+ return alloca;
+ }
+ /// Function that generates a FIR operation accessing the descriptor's
+ /// base address (BoxOffsetOp) and a MapInfoOp for it. The most
+ /// important thing to note is that we normally move the bounds from
+ /// the descriptor map onto the base address map.
+ mlir::omp::MapInfoOp genBaseAddrMap(mlir::Value descriptor,
+ mlir::OperandRange bounds,
+ int64_t mapType,
+ fir::FirOpBuilder &builder) {
+ mlir::Location loc = descriptor.getLoc();
mlir::Value baseAddrAddr = builder.create<fir::BoxOffsetOp>(
loc, descriptor, fir::BoxFieldAttr::base_addr);
// Member of the descriptor pointing at the allocated data
- mlir::Value baseAddr = builder.create<mlir::omp::MapInfoOp>(
+ return builder.create<mlir::omp::MapInfoOp>(
loc, baseAddrAddr.getType(), descriptor,
mlir::TypeAttr::get(llvm::cast<mlir::omp::PointerLikeType>(
fir::unwrapRefType(baseAddrAddr.getType()))
.getElementType()),
baseAddrAddr, /*members=*/mlir::SmallVector<mlir::Value>{},
- /*member_index=*/mlir::DenseIntElementsAttr{}, op.getBounds(),
- builder.getIntegerAttr(builder.getIntegerType(64, false),
- op.getMapType().value()),
+ /*membersIndex=*/mlir::ArrayAttr{}, bounds,
+ builder.getIntegerAttr(builder.getIntegerType(64, false), mapType),
builder.getAttr<mlir::omp::VariableCaptureKindAttr>(
mlir::omp::VariableCaptureKind::ByRef),
/*name=*/builder.getStringAttr(""),
/*partial_map=*/builder.getBoolAttr(false));
+ }
+
+ /// This function adjusts the member indices vector to include a new
+ /// base address member. We take the position of the descriptor in
+ /// the member indices list, which is the index data that the base
+ /// addresses index will be based off of, as the base address is
+ /// a member of the descriptor. We must also alter other members
+ /// that are members of this descriptor to account for the addition
+ /// of the base address index.
+ void adjustMemberIndices(
+ llvm::SmallVectorImpl<llvm::SmallVector<int64_t>> &memberIndices,
+ size_t memberIndex) {
+ llvm::SmallVector<int64_t> baseAddrIndex = memberIndices[memberIndex];
+
+ // If we find another member that is "derived/a member of" the descriptor
+ // that is not the descriptor itself, we must insert a 0 for the new base
+ // address we have just added for the descriptor into the list at the
+ // appropriate position to maintain correctness of the positional/index data
+ // for that member.
+ for (llvm::SmallVector<int64_t> &member : memberIndices)
+ if (member.size() > baseAddrIndex.size() &&
+ std::equal(baseAddrIndex.begin(), baseAddrIndex.end(),
+ member.begin()))
+ member.insert(std::next(member.begin(), baseAddrIndex.size()), 0);
+
+ // Add the base address index to the main base address member data
+ baseAddrIndex.push_back(0);
+
+ // Insert our newly created baseAddrIndex into the larger list of indices at
+ // the correct location.
+ memberIndices.insert(std::next(memberIndices.begin(), memberIndex + 1),
+ baseAddrIndex);
+ }
+
+ /// Adjusts the descriptor's map type. The main alteration that is done
+ /// currently is transforming the map type to `OMP_MAP_TO` where possible.
+ /// This is because we will always need to map the descriptor to device
+ /// (or at the very least it seems to be the case currently with the
+ /// current lowered kernel IR), as without the appropriate descriptor
+ /// information on the device there is a risk of the kernel IR
+ /// requesting for various data that will not have been copied to
+ /// perform things like indexing. This can cause segfaults and
+ /// memory access errors. However, we do not need this data mapped
+ /// back to the host from the device, as per the OpenMP spec we cannot alter
+ /// the data via resizing or deletion on the device. Discarding any
+ /// descriptor alterations via no map back is reasonable (and required
+ /// for certain segments of descriptor data like the type descriptor that are
+ /// global constants). This alteration is only inapplicable to `target exit`
+ /// and `target update` currently, and that's due to `target exit` not
+ /// allowing `to` mappings, and `target update` not allowing both `to` and
+ /// `from` simultaneously. We currently try to maintain the `implicit` flag
+ /// where necessary, although it does not seem strictly required.
+ unsigned long getDescriptorMapType(unsigned long mapTypeFlag,
+ mlir::Operation *target) {
+ if (llvm::isa_and_nonnull<mlir::omp::TargetExitDataOp,
+ mlir::omp::TargetUpdateOp>(target))
+ return mapTypeFlag;
+
+ bool hasImplicitMap =
+ (llvm::omp::OpenMPOffloadMappingFlags(mapTypeFlag) &
+ llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT) ==
+ llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT;
+
+ return llvm::to_underlying(
+ hasImplicitMap
+ ? llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO |
+ llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_IMPLICIT
+ : llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TO);
+ }
+
+ mlir::omp::MapInfoOp genDescriptorMemberMaps(mlir::omp::MapInfoOp op,
+ fir::FirOpBuilder &builder,
+ mlir::Operation *target) {
+ llvm::SmallVector<ParentAndPlacement> mapMemberUsers;
+ getMemberUserList(op, mapMemberUsers);
// TODO: map the addendum segment of the descriptor, similarly to the
- // above base address/data pointer member.
+ // base address/data pointer member.
+ mlir::Value descriptor = getDescriptorFromBoxMap(op, builder);
+ auto baseAddr = genBaseAddrMap(descriptor, op.getBounds(),
+ op.getMapType().value_or(0), builder);
+ mlir::ArrayAttr newMembersAttr;
+ mlir::SmallVector<mlir::Value> newMembers;
+ llvm::SmallVector<llvm::SmallVector<int64_t>> memberIndices;
- auto addOperands = [&](mlir::OperandRange &operandsArr,
- mlir::MutableOperandRange &mutableOpRange,
- auto directiveOp) {
- llvm::SmallVector<mlir::Value> newMapOps;
- for (size_t i = 0; i < operandsArr.size(); ++i) {
- if (operandsArr[i] == op) {
- // Push new implicit maps generated for the descriptor.
- newMapOps.push_back(baseAddr);
-
- // for TargetOp's which have IsolatedFromAbove we must align the
- // new additional map operand with an appropriate BlockArgument,
- // as the printing and later processing currently requires a 1:1
- // mapping of BlockArgs to MapInfoOp's at the same placement in
- // each array (BlockArgs and MapOperands).
- if (directiveOp) {
- directiveOp.getRegion().insertArgument(i, baseAddr.getType(), loc);
- }
- }
- newMapOps.push_back(operandsArr[i]);
+ if (!mapMemberUsers.empty() || !op.getMembers().empty())
+ getMemberIndicesAsVectors(
+ !mapMemberUsers.empty() ? mapMemberUsers[0].parent : op,
+ memberIndices);
+
+ // If the operation that we are expanding with a descriptor has a user
+ // (parent), then we have to expand the parent's member indices to reflect
+ // the adjusted member indices for the base address insertion. However, if
+ // it does not then we are expanding a MapInfoOp without any pre-existing
+ // member information to now have one new member for the base address, or
+ // we are expanding a parent that is a descriptor and we have to adjust
+ // all of its members to reflect the insertion of the base address.
+ if (!mapMemberUsers.empty()) {
+ // Currently, there should only be one user per map when this pass
+ // is executed. Either a parent map, holding the current map in its
+ // member list, or a target operation that holds a map clause. This
+ // may change in the future if we aim to refactor the MLIR for map
+ // clauses to allow sharing of duplicate maps across target
+ // operations.
+ assert(mapMemberUsers.size() == 1 &&
+ "OMPMapInfoFinalization currently only supports single users of a "
+ "MapInfoOp");
+ ParentAndPlacement mapUser = mapMemberUsers[0];
+ adjustMemberIndices(memberIndices, mapUser.index);
+ llvm::SmallVector<mlir::Value> newMemberOps;
+ for (auto v : mapUser.parent.getMembers()) {
+ newMemberOps.push_back(v);
+ if (v == op)
+ newMemberOps.push_back(baseAddr);
+ }
+ mapUser.parent.getMembersMutable().assign(newMemberOps);
+ mapUser.parent.setMembersIndexAttr(
+ builder.create2DI64ArrayAttr(memberIndices));
+ } else {
+ newMembers.push_back(baseAddr);
+ if (!op.getMembers().empty()) {
+ for (auto &indices : memberIndices)
+ indices.insert(indices.begin(), 0);
+ memberIndices.insert(memberIndices.begin(), {0});
+ newMembersAttr = builder.create2DI64ArrayAttr(memberIndices);
+ newMembers.append(op.getMembers().begin(), op.getMembers().end());
+ } else {
+ llvm::SmallVector<llvm::SmallVector<int64_t>> memberIdx = {{0}};
+ newMembersAttr = builder.create2DI64ArrayAttr(memberIdx);
}
- mutableOpRange.assign(newMapOps);
- };
- if (auto mapClauseOwner =
- llvm::dyn_cast<mlir::omp::MapClauseOwningOpInterface>(target)) {
- mlir::OperandRange mapOperandsArr = mapClauseOwner.getMapVars();
- mlir::MutableOperandRange mapMutableOpRange =
- mapClauseOwner.getMapVarsMutable();
- mlir::omp::TargetOp targetOp =
- llvm::dyn_cast<mlir::omp::TargetOp>(target);
- addOperands(mapOperandsArr, mapMutableOpRange, targetOp);
- }
- if (auto targetDataOp = llvm::dyn_cast<mlir::omp::TargetDataOp>(target)) {
- mlir::OperandRange useDevAddrArr = targetDataOp.getUseDeviceAddrVars();
- mlir::MutableOperandRange useDevAddrMutableOpRange =
- targetDataOp.getUseDeviceAddrVarsMutable();
- addOperands(useDevAddrArr, useDevAddrMutableOpRange, targetDataOp);
}
- mlir::Value newDescParentMapOp = builder.create<mlir::omp::MapInfoOp>(
- op->getLoc(), op.getResult().getType(), descriptor,
- mlir::TypeAttr::get(fir::unwrapRefType(descriptor.getType())),
- /*varPtrPtr=*/mlir::Value{},
- /*members=*/mlir::SmallVector<mlir::Value>{baseAddr},
- /*members_index=*/
- mlir::DenseIntElementsAttr::get(
- mlir::VectorType::get(
- llvm::ArrayRef<int64_t>({1, 1}),
- mlir::IntegerType::get(builder.getContext(), 32)),
- llvm::ArrayRef<int32_t>({0})),
- /*bounds=*/mlir::SmallVector<mlir::Value>{},
- builder.getIntegerAttr(builder.getIntegerType(64, false),
- op.getMapType().value()),
- op.getMapCaptureTypeAttr(), op.getNameAttr(), op.getPartialMapAttr());
- op.replaceAllUsesWith(newDescParentMapOp);
+ mlir::omp::MapInfoOp newDescParentMapOp =
+ builder.create<mlir::omp::MapInfoOp>(
+ op->getLoc(), op.getResult().getType(), descriptor,
+ mlir::TypeAttr::get(fir::unwrapRefType(descriptor.getType())),
+ /*varPtrPtr=*/mlir::Value{}, newMembers, newMembersAttr,
+ /*bounds=*/mlir::SmallVector<mlir::Value>{},
+ builder.getIntegerAttr(
+ builder.getIntegerType(64, false),
+ getDescriptorMapType(op.getMapType().value_or(0), target)),
+ op.getMapCaptureTypeAttr(), op.getNameAttr(),
+ /*partial_map=*/builder.getBoolAttr(false));
+ op.replaceAllUsesWith(newDescParentMapOp.getResult());
op->erase();
+ return newDescParentMapOp;
}
// We add all mapped record members not directly used in the target region
@@ -225,32 +362,78 @@ class MapInfoFinalizationPass
fir::FirOpBuilder &builder,
mlir::Operation *target) {
auto mapClauseOwner =
- llvm::dyn_cast<mlir::omp::MapClauseOwningOpInterface>(target);
+ llvm::dyn_cast_if_present<mlir::omp::MapClauseOwningOpInterface>(
+ target);
+ // TargetDataOp is technically a MapClauseOwningOpInterface, so we
+ // do not need to explicitly check for the extra cases here for use_device
+ // addr/ptr
if (!mapClauseOwner)
return;
- llvm::SmallVector<mlir::Value> newMapOps;
- mlir::OperandRange mapVarsArr = mapClauseOwner.getMapVars();
- auto targetOp = llvm::dyn_cast<mlir::omp::TargetOp>(target);
+ auto addOperands = [&](mlir::MutableOperandRange &mapVarsArr,
+ mlir::Operation *directiveOp,
+ unsigned mapArgsStart = 0) {
+ llvm::SmallVector<mlir::Value> newMapOps;
+ for (auto [i, mapVar] : llvm::enumerate(mapVarsArr)) {
+ if (mapVar.get() != op) {
+ newMapOps.push_back(mapVar.get());
+ continue;
+ }
- for (size_t i = 0; i < mapVarsArr.size(); ++i) {
- if (mapVarsArr[i] == op) {
for (auto [j, mapMember] : llvm::enumerate(op.getMembers())) {
newMapOps.push_back(mapMember);
- // for TargetOp's which have IsolatedFromAbove we must align the
- // new additional map operand with an appropriate BlockArgument,
- // as the printing and later processing currently requires a 1:1
- // mapping of BlockArgs to MapInfoOp's at the same placement in
- // each array (BlockArgs and MapVars).
- if (targetOp) {
- targetOp.getRegion().insertArgument(i + j, mapMember.getType(),
- targetOp->getLoc());
- }
+ if (directiveOp)
+ directiveOp->getRegion(0).insertArgument(
+ mapArgsStart + i + j, mapMember.getType(), mapMember.getLoc());
}
+ newMapOps.push_back(mapVar.get());
}
- newMapOps.push_back(mapVarsArr[i]);
+ mapVarsArr.assign(newMapOps);
+ };
+
+ auto argIface =
+ llvm::dyn_cast<mlir::omp::BlockArgOpenMPOpInterface>(target);
+
+ if (auto mapClauseOwner =
+ llvm::dyn_cast<mlir::omp::MapClauseOwningOpInterface>(target)) {
+ mlir::MutableOperandRange mapVarsArr = mapClauseOwner.getMapVarsMutable();
+ unsigned blockArgInsertIndex =
+ argIface ? argIface.getMapBlockArgsStart() : 0;
+ addOperands(mapVarsArr, llvm::dyn_cast<mlir::omp::TargetOp>(target),
+ blockArgInsertIndex);
+ }
+
+ if (auto targetDataOp = llvm::dyn_cast<mlir::omp::TargetDataOp>(target)) {
+ mlir::MutableOperandRange useDevAddrArr =
+ targetDataOp.getUseDeviceAddrVarsMutable();
+ addOperands(useDevAddrArr, target,
+ argIface.getUseDeviceAddrBlockArgsStart());
}
- mapClauseOwner.getMapVarsMutable().assign(newMapOps);
+ }
+
+ // We retrieve the first user that is a Target operation, of which
+ // there should only be one currently. Every MapInfoOp can be tied to
+ // at most one Target operation and at the minimum no operations.
+ // This may change in the future with IR cleanups/modifications,
+ // in which case this pass will need updating to support cases
+ // where a map can have more than one user and more than one of
+ // those users can be a Target operation. For now, we simply
+ // return the first target operation encountered, which may
+ // be on the parent MapInfoOp in the case of a member mapping.
+ // In that case, we traverse the MapInfoOp chain until we
+ // find the first TargetOp user.
+ mlir::Operation *getFirstTargetUser(mlir::omp::MapInfoOp mapOp) {
+ for (auto *user : mapOp->getUsers()) {
+ if (llvm::isa<mlir::omp::TargetOp, mlir::omp::TargetDataOp,
+ mlir::omp::TargetUpdateOp, mlir::omp::TargetExitDataOp,
+ mlir::omp::TargetEnterDataOp>(user))
+ return user;
+
+ if (auto mapUser = llvm::dyn_cast<mlir::omp::MapInfoOp>(user))
+ return getFirstTargetUser(mapUser);
+ }
+
+ return nullptr;
}
// This pass executes on omp::MapInfoOp's containing descriptor based types
@@ -283,27 +466,39 @@ class MapInfoFinalizationPass
localBoxAllocas.clear();
func->walk([&](mlir::omp::MapInfoOp op) {
- // TODO: Currently only supports a single user for the MapInfoOp, this
- // is fine for the moment as the Fortran Frontend will generate a
- // new MapInfoOp per Target operation for the moment. However, when/if
- // we optimise/cleanup the IR, it likely isn't too difficult to
- // extend this function, it would require some modification to create a
- // single new MapInfoOp per new MapInfoOp generated and share it across
- // all users appropriately, making sure to only add a single member link
- // per new generation for the original originating descriptor MapInfoOp.
+ // TODO: Currently only supports a single user for the MapInfoOp. This
+ // is fine for the moment, as the Fortran frontend will generate a
+ // new MapInfoOp with at most one user currently. In the case of
+ // members of other objects, like derived types, the user would be the
+ // parent. In cases where it's a regular non-member map, the user would
+ // be the target operation it is being mapped by.
+ //
+ // However, when/if we optimise/cleanup the IR we will have to extend
+ // 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");
- if (!op.getMembers().empty()) {
- addImplicitMembersToTarget(op, builder, *op->getUsers().begin());
- } else if (fir::isTypeWithDescriptor(op.getVarType()) ||
- mlir::isa_and_present<fir::BoxAddrOp>(
- op.getVarPtr().getDefiningOp())) {
+ if (fir::isTypeWithDescriptor(op.getVarType()) ||
+ mlir::isa_and_present<fir::BoxAddrOp>(
+ op.getVarPtr().getDefiningOp())) {
builder.setInsertionPoint(op);
- genDescriptorMemberMaps(op, builder, *op->getUsers().begin());
+ mlir::Operation *targetUser = getFirstTargetUser(op);
+ assert(targetUser && "expected user of map operation was not found");
+ genDescriptorMemberMaps(op, builder, targetUser);
}
});
+
+ // Wait until after we have generated all of our maps to add them onto
+ // the target's block arguments, simplifying the process as there would be
+ // no need to avoid accidental duplicate additions.
+ 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);
+ });
});
}
};
diff --git a/flang/lib/Optimizer/OpenMP/MapsForPrivatizedSymbols.cpp b/flang/lib/Optimizer/OpenMP/MapsForPrivatizedSymbols.cpp
index 2fa55844aec7c7..289e648eed8546 100644
--- a/flang/lib/Optimizer/OpenMP/MapsForPrivatizedSymbols.cpp
+++ b/flang/lib/Optimizer/OpenMP/MapsForPrivatizedSymbols.cpp
@@ -92,7 +92,7 @@ class MapsForPrivatizedSymbolsPass
.getElementType()),
/*varPtrPtr=*/Value{},
/*members=*/SmallVector<Value>{},
- /*member_index=*/DenseIntElementsAttr{},
+ /*member_index=*/mlir::ArrayAttr{},
/*bounds=*/ValueRange{},
builder.getIntegerAttr(builder.getIntegerType(64, /*isSigned=*/false),
mapTypeTo),
diff --git a/flang/test/Fir/convert-to-llvm-openmp-and-fir.fir b/flang/test/Fir/convert-to-llvm-openmp-and-fir.fir
index 184abe24fe967d..6db86e0d5f642a 100644
--- a/flang/test/Fir/convert-to-llvm-openmp-and-fir.fir
+++ b/flang/test/Fir/convert-to-llvm-openmp-and-fir.fir
@@ -985,8 +985,8 @@ func.func @omp_map_info_nested_derived_type_explicit_member_conversion(%arg0 : !
%6 = fir.coordinate_of %arg0, %5 : (!fir.ref<!fir.type<_QFTtop_layer{array_i:!fir.array<10xi32>,nested:!fir.type<_QFTbottom_layer{array_i2:!fir.array<10xf32>,i2:f64}>,k:i32}>>, !fir.field) -> !fir.ref<i32>
// CHECK: %[[MAP_MEMBER_2:.*]] = omp.map.info var_ptr(%[[GEP_3]] : !llvm.ptr, i32) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr
%7 = omp.map.info var_ptr(%6 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32>
- // CHECK: %[[PARENT_MAP:.*]] = omp.map.info var_ptr(%[[ARG_0]] : !llvm.ptr, !llvm.struct<"_QFTtop_layer", (array<10 x i32>, struct<"_QFTbottom_layer", (array<10 x f32>, f64)>, i32)>) map_clauses(tofrom) capture(ByRef) members(%[[MAP_MEMBER_1]], %[[MAP_MEMBER_2]] : [1,1], [2,-1] : !llvm.ptr, !llvm.ptr) -> !llvm.ptr {partial_map = true}
- %9 = omp.map.info var_ptr(%arg0 : !fir.ref<!fir.type<_QFTtop_layer{array_i:!fir.array<10xi32>,nested:!fir.type<_QFTbottom_layer{array_i2:!fir.array<10xf32>,i2:f64}>,k:i32}>>, !fir.type<_QFTtop_layer{array_i:!fir.array<10xi32>,nested:!fir.type<_QFTbottom_layer{array_i2:!fir.array<10xf32>,i2:f64}>,k:i32}>) map_clauses(tofrom) capture(ByRef) members(%4, %7 : [1,1], [2,-1] : !fir.ref<f64>, !fir.ref<i32>) -> !fir.ref<!fir.type<_QFTtop_layer{array_i:!fir.array<10xi32>,nested:!fir.type<_QFTbottom_layer{array_i2:!fir.array<10xf32>,i2:f64}>,k:i32}>> {partial_map = true}
+ // CHECK: %[[PARENT_MAP:.*]] = omp.map.info var_ptr(%[[ARG_0]] : !llvm.ptr, !llvm.struct<"_QFTtop_layer", (array<10 x i32>, struct<"_QFTbottom_layer", (array<10 x f32>, f64)>, i32)>) map_clauses(tofrom) capture(ByRef) members(%[[MAP_MEMBER_1]], %[[MAP_MEMBER_2]] : [1, 1], [2] : !llvm.ptr, !llvm.ptr) -> !llvm.ptr {partial_map = true}
+ %9 = omp.map.info var_ptr(%arg0 : !fir.ref<!fir.type<_QFTtop_layer{array_i:!fir.array<10xi32>,nested:!fir.type<_QFTbottom_layer{array_i2:!fir.array<10xf32>,i2:f64}>,k:i32}>>, !fir.type<_QFTtop_layer{array_i:!fir.array<10xi32>,nested:!fir.type<_QFTbottom_layer{array_i2:!fir.array<10xf32>,i2:f64}>,k:i32}>) map_clauses(tofrom) capture(ByRef) members(%4, %7 : [1,1], [2] : !fir.ref<f64>, !fir.ref<i32>) -> !fir.ref<!fir.type<_QFTtop_layer{array_i:!fir.array<10xi32>,nested:!fir.type<_QFTbottom_layer{array_i2:!fir.array<10xf32>,i2:f64}>,k:i32}>> {partial_map = true}
// CHECK: omp.target map_entries(%[[MAP_MEMBER_1]] -> %{{.*}}, %[[MAP_MEMBER_2]] -> %{{.*}}, %[[PARENT_MAP]] -> %{{.*}} : !llvm.ptr, !llvm.ptr, !llvm.ptr) {
omp.target map_entries(%4 -> %arg1, %7 -> %arg2, %9 -> %arg3 : !fir.ref<f64>, !fir.ref<i32>, !fir.ref<!fir.type<_QFTtop_layer{array_i:!fir.array<10xi32>,nested:!fir.type<_QFTbottom_layer{array_i2:!fir.array<10xf32>,i2:f64}>,k:i32}>>) {
omp.terminator
@@ -1065,3 +1065,165 @@ func.func @omp_map_common_block_using_common_block_members() {
}
fir.global common @var_common_(dense<0> : vector<8xi8>) {alignment = 4 : i64} : !fir.array<8xi8>
+
+// -----
+
+// NOTE: This test (and the other allocatable member map tests below) uses mock
+// bounds to simplify the example, the real bounds generation is more complex
+// as it has to access the box information. However, it's not what the test
+// aims to check. The test aims to check the parent member bindings and
+// acceses are appropriately maintained when lowering to the LLVM dialect.
+
+// CHECK-LABEL: llvm.func @map_dtype_alloca_mem
+// CHECK-SAME: %[[ARG_0:.*]]: !llvm.ptr)
+func.func @map_dtype_alloca_mem(%arg0 : !fir.ref<!fir.type<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>) {
+ %c4 = arith.constant 4 : index
+ %c1 = arith.constant 1 : index
+ %c0 = arith.constant 0 : index
+ // CHECK: %[[BOUNDS:.*]] = omp.map.bounds lower_bound({{.*}}) upper_bound({{.*}}) extent({{.*}}) stride({{.*}}) start_idx({{.*}}) {stride_in_bytes = true}
+ %0 = omp.map.bounds lower_bound(%c0 : index) upper_bound(%c4 : index) extent(%c4 : index) stride(%c1 : index) start_idx(%c0 : index) {stride_in_bytes = true}
+ // CHECK: %[[GEP:.*]] = llvm.getelementptr %[[ARG_0]][0, 4] : (!llvm.ptr) -> !llvm.ptr, [[STRUCT_TY:!llvm.struct<"_QFRecTy", \(f32, struct<\(ptr, i64, i32, i8, i8, i8, i8\)>, array<10 x i32>, f32, struct<\(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>\)>, i32\)>]]
+ %1 = fir.coordinate_of %arg0, %c4 : (!fir.ref<!fir.type<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>, index) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ // CHECK: %[[BADDR_GEP:.*]] = llvm.getelementptr %[[GEP]][0, 0] : (!llvm.ptr) -> !llvm.ptr, [[STRUCT_TY2:!llvm.struct<\(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>\)>]]
+ %2 = fir.box_offset %1 base_addr : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>
+ // CHECK: %[[MAP_MEMBER_BADDR:.*]] = omp.map.info var_ptr(%[[GEP]] : !llvm.ptr, i32) var_ptr_ptr(%[[BADDR_GEP]] : !llvm.ptr) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS]]) -> !llvm.ptr
+ %3 = omp.map.info var_ptr(%1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.array<?xi32>) var_ptr_ptr(%2 : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) map_clauses(tofrom) capture(ByRef) bounds(%0) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>
+ // CHECK: %[[MAP_MEMBER_DESCRIPTOR:.*]] = omp.map.info var_ptr(%[[GEP]] : !llvm.ptr, [[STRUCT_TY2]]) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr
+ %4 = omp.map.info var_ptr(%1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.box<!fir.heap<!fir.array<?xi32>>>) map_clauses(tofrom) capture(ByRef) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ // CHECK: %[[MAP_PARENT_DTYPE:.*]] = omp.map.info var_ptr(%[[ARG_0]] : !llvm.ptr, [[STRUCT_TY]]) map_clauses(tofrom) capture(ByRef) members(%[[MAP_MEMBER_DESCRIPTOR]], %[[MAP_MEMBER_BADDR]] : [4], [4, 0] : !llvm.ptr, !llvm.ptr) -> !llvm.ptr {partial_map = true}
+ %5 = omp.map.info var_ptr(%arg0 : !fir.ref<!fir.type<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>, !fir.type<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>) map_clauses(tofrom) capture(ByRef) members(%4, %3 : [4], [4,0] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) -> !fir.ref<!fir.type<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>> {partial_map = true}
+ // CHECK: omp.target map_entries(%[[MAP_MEMBER_DESCRIPTOR]] -> %[[ARG_1:.*]], %[[MAP_MEMBER_BADDR]] -> %[[ARG_2:.*]], %[[MAP_PARENT_DTYPE]] -> %[[ARG_3:.*]] : !llvm.ptr, !llvm.ptr, !llvm.ptr) {
+ omp.target map_entries(%4 -> %arg1, %3 -> %arg2, %5 -> %arg3 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>, !fir.ref<!fir.type<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>) {
+ omp.terminator
+ }
+ return
+}
+
+// -----
+
+// CHECK-LABEL: llvm.func @map_dtype_alloca_mem2
+// CHECK-SAME: %[[ARG_0:.*]]: !llvm.ptr)
+func.func @map_dtype_alloca_mem2(%arg0 : !fir.ref<!fir.box<!fir.heap<!fir.type<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>>>) {
+ // CHECK: %[[DTYPE_ALLOCATABLE_ALOCA_2:.*]] = llvm.alloca {{.*}} x [[DESC_TY:!llvm.struct<\(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>\)>]] {alignment = 8 : i64} : (i32) -> !llvm.ptr
+ // CHECK: %[[DTYPE_ALLOCATABLE_ALOCA:.*]] = llvm.alloca {{.*}} x [[DESC_TY]] {alignment = 8 : i64} : (i32) -> !llvm.ptr
+ %c5 = arith.constant 5 : index
+ %c4 = arith.constant 4 : index
+ %c1 = arith.constant 1 : index
+ %c0 = arith.constant 0 : index
+ // CHECK: %[[BOUNDS:.*]] = omp.map.bounds lower_bound({{.*}}) upper_bound({{.*}}) extent({{.*}}) stride({{.*}}) start_idx({{.*}}) {stride_in_bytes = true}
+ %0 = omp.map.bounds lower_bound(%c0 : index) upper_bound(%c4 : index) extent(%c4 : index) stride(%c1 : index) start_idx(%c0 : index) {stride_in_bytes = true}
+ // CHECK: "llvm.intr.memcpy"(%[[DTYPE_ALLOCATABLE_ALOCA]], %[[ARG_0]], {{.*}}) <{isVolatile = false}> : (!llvm.ptr, !llvm.ptr, i32) -> ()
+ %1 = fir.load %arg0 : !fir.ref<!fir.box<!fir.heap<!fir.type<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>>>
+ // CHECK: %[[GEP_DTYPE_BADDR:.*]] = llvm.getelementptr %[[DTYPE_ALLOCATABLE_ALOCA]][0, 0] : (!llvm.ptr) -> !llvm.ptr, [[DESC_TY]]
+ // CHECK: %[[LOAD_DTYPE_BADDR:.*]] = llvm.load %[[GEP_DTYPE_BADDR]] : !llvm.ptr -> !llvm.ptr
+ // CHECK: %[[GEP_DTYPE_MEMBER:.*]] = llvm.getelementptr %[[LOAD_DTYPE_BADDR]][0, 4] : (!llvm.ptr) -> !llvm.ptr, [[REC_TY:!llvm.struct<"_QFRecTy", \(f32, struct<\(ptr, i64, i32, i8, i8, i8, i8\)>, array<10 x i32>, f32, struct<\(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>\)>, i32\)>]]
+ %2 = fir.coordinate_of %1, %c4 : (!fir.box<!fir.heap<!fir.type<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>>, index) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ // CHECK: %[[DTYPE_MEMBER_BADDR:.*]] = llvm.getelementptr %[[GEP_DTYPE_MEMBER]][0, 0] : (!llvm.ptr) -> !llvm.ptr, [[DESC_TY2:!llvm.struct<\(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>\)>]]
+ %3 = fir.box_offset %2 base_addr : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>
+ // CHECK: %[[MAP_MEMBER_BADDR:.*]] = omp.map.info var_ptr(%[[GEP_DTYPE_MEMBER]] : !llvm.ptr, i32) var_ptr_ptr(%[[DTYPE_MEMBER_BADDR]] : !llvm.ptr) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS]]) -> !llvm.ptr
+ %4 = omp.map.info var_ptr(%2 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.array<?xi32>) var_ptr_ptr(%3 : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) map_clauses(tofrom) capture(ByRef) bounds(%0) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>
+ // CHECK: %[[MAP_MEMBER_DESC:.*]] = omp.map.info var_ptr(%[[GEP_DTYPE_MEMBER]] : !llvm.ptr, [[DESC_TY2]]) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr
+ %5 = omp.map.info var_ptr(%2 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.box<!fir.heap<!fir.array<?xi32>>>) map_clauses(tofrom) capture(ByRef) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ // CHECK: "llvm.intr.memcpy"(%[[DTYPE_ALLOCATABLE_ALOCA_2]], %[[ARG_0]], {{.*}}) <{isVolatile = false}> : (!llvm.ptr, !llvm.ptr, i32) -> ()
+ %6 = fir.load %arg0 : !fir.ref<!fir.box<!fir.heap<!fir.type<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>>>
+ // CHECK: %[[GEP_DTYPE_BADDR:.*]] = llvm.getelementptr %[[DTYPE_ALLOCATABLE_ALOCA_2]][0, 0] : (!llvm.ptr) -> !llvm.ptr, [[DESC_TY]]
+ // CHECK: %[[LOAD_DTYPE_BADDR:.*]] = llvm.load %[[GEP_DTYPE_BADDR]] : !llvm.ptr -> !llvm.ptr
+ // CHECK: %[[GEP_DTYPE_REGULAR_MEMBER:.*]] = llvm.getelementptr %[[LOAD_DTYPE_BADDR]][0, 5] : (!llvm.ptr) -> !llvm.ptr, [[REC_TY]]
+ %7 = fir.coordinate_of %6, %c5 : (!fir.box<!fir.heap<!fir.type<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>>, index) -> !fir.ref<i32>
+ // CHECK: %[[MAP_REGULAR_MEMBER:.*]] = omp.map.info var_ptr(%[[GEP_DTYPE_REGULAR_MEMBER]] : !llvm.ptr, i32) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr
+ %8 = omp.map.info var_ptr(%7 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32>
+ // CHECK: %[[GEP_DTYPE_BADDR:.*]] = llvm.getelementptr %[[ARG_0]][0, 0] : (!llvm.ptr) -> !llvm.ptr, [[DESC_TY]]
+ %9 = fir.box_offset %arg0 base_addr : (!fir.ref<!fir.box<!fir.heap<!fir.type<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>>>) -> !fir.llvm_ptr<!fir.ref<!fir.type<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>>
+ // CHECK: %[[MAP_DTYPE_PARENT_BADDR:.*]] = omp.map.info var_ptr(%[[ARG_0]] : !llvm.ptr, [[REC_TY]]) var_ptr_ptr(%[[GEP_DTYPE_BADDR]] : !llvm.ptr) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr
+ %10 = omp.map.info var_ptr(%arg0 : !fir.ref<!fir.box<!fir.heap<!fir.type<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>>>, !fir.type<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>) var_ptr_ptr(%9 : !fir.llvm_ptr<!fir.ref<!fir.type<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>>) map_clauses(tofrom) capture(ByRef) -> !fir.llvm_ptr<!fir.ref<!fir.type<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>>
+ // CHECK: %[[MAP_DTYPE_PARENT_DESC:.*]] = omp.map.info var_ptr(%[[ARG_0]] : !llvm.ptr, [[DESC_TY]]) map_clauses(tofrom) capture(ByRef) members(%[[MAP_DTYPE_PARENT_BADDR]], %[[MAP_MEMBER_DESC]], %[[MAP_MEMBER_BADDR]], %[[MAP_REGULAR_MEMBER]] : [0], [0, 4], [0, 4, 0], [0, 5] : !llvm.ptr, !llvm.ptr, !llvm.ptr, !llvm.ptr) -> !llvm.ptr
+ %11 = omp.map.info var_ptr(%arg0 : !fir.ref<!fir.box<!fir.heap<!fir.type<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>>>, !fir.box<!fir.heap<!fir.type<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>>) map_clauses(tofrom) capture(ByRef) members(%10, %5, %4, %8 : [0], [0,4], [0,4,0], [0,5] : !fir.llvm_ptr<!fir.ref<!fir.type<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>>, !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<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>>>
+ // CHECK: omp.target map_entries(%[[MAP_DTYPE_PARENT_BADDR]] -> %[[ARG_1:.*]], %[[MAP_MEMBER_DESC]] -> %[[ARG_2:.*]], %[[MAP_MEMBER_BADDR]] -> %[[ARG_3:.*]], %[[MAP_REGULAR_MEMBER]] -> %[[ARG_4:.*]], %[[MAP_DTYPE_PARENT_DESC]] -> %[[ARG_5:.*]] : !llvm.ptr, !llvm.ptr, !llvm.ptr, !llvm.ptr, !llvm.ptr) {
+ omp.target map_entries(%10 -> %arg1, %5 -> %arg2, %4 -> %arg3, %8 -> %arg4, %11 -> %arg5 : !fir.llvm_ptr<!fir.ref<!fir.type<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>>, !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<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>>>) {
+ omp.terminator
+ }
+ return
+}
+
+// -----
+
+// CHECK-LABEL: llvm.func @map_nested_dtype_alloca_mem
+// CHECK-SAME: %[[ARG_0:.*]]: !llvm.ptr)
+func.func @map_nested_dtype_alloca_mem(%arg0 : !fir.ref<!fir.box<!fir.heap<!fir.type<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFRecTy2{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>>>) {
+ // CHECK: %[[DTYPE_ALLOCATABLE_ALOCA_2:.*]] = llvm.alloca {{.*}} x [[DESC_TY:!llvm.struct<\(ptr, i64, i32, i8, i8, i8, i8, ptr, array<1 x i64>\)>]] {alignment = 8 : i64} : (i32) -> !llvm.ptr
+ // CHECK: %[[DTYPE_ALLOCATABLE_ALOCA:.*]] = llvm.alloca {{.*}} x [[DESC_TY]] {alignment = 8 : i64} : (i32) -> !llvm.ptr
+ %c3 = arith.constant 3 : index
+ %c4 = arith.constant 4 : index
+ %c6 = arith.constant 6 : index
+ %c1 = arith.constant 1 : index
+ %c2 = arith.constant 2 : index
+ %c0 = arith.constant 0 : index
+ // CHECK: %[[BOUNDS:.*]] = omp.map.bounds lower_bound({{.*}}) upper_bound({{.*}}) extent({{.*}}) stride({{.*}}) start_idx({{.*}}) {stride_in_bytes = true}
+ %0 = omp.map.bounds lower_bound(%c0 : index) upper_bound(%c4 : index) extent(%c4 : index) stride(%c1 : index) start_idx(%c0 : index) {stride_in_bytes = true}
+ // CHECK: "llvm.intr.memcpy"(%[[DTYPE_ALLOCATABLE_ALOCA]], %[[ARG_0]], {{.*}}) <{isVolatile = false}> : (!llvm.ptr, !llvm.ptr, i32) -> ()
+ %1 = fir.load %arg0 : !fir.ref<!fir.box<!fir.heap<!fir.type<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFRecTy2{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>>>
+ // CHECK: %[[GEP_DTYPE_BADDR:.*]] = llvm.getelementptr %[[DTYPE_ALLOCATABLE_ALOCA]][0, 0] : (!llvm.ptr) -> !llvm.ptr, [[DESC_TY]]
+ // CHECK: %[[LOAD_GEP_DTYPE_BADDR:.*]] = llvm.load %[[GEP_DTYPE_BADDR]] : !llvm.ptr -> !llvm.ptr
+ // CHECK: %[[LOAD_NESTED_DTYPE:.*]] = llvm.getelementptr %[[LOAD_GEP_DTYPE_BADDR]][0, 6] : (!llvm.ptr) -> !llvm.ptr, [[REC_TY:!llvm.struct<"_QFRecTy", \(f32, struct<\(ptr, i64, i32, i8, i8, i8, i8\)>, array<10 x i32>, f32, struct<\(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>\)>, i32, struct<"_QFRecTy2", \(f32, array<10 x i32>, struct<\(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>\)>, i32\)>\)>]]
+ %2 = fir.coordinate_of %1, %c6 : (!fir.box<!fir.heap<!fir.type<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFRecTy2{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>>, index) -> !fir.ref<!fir.type<_QFRecTy2{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>
+ // CHECK: %[[GEP_NESTED_DTYPE_ALLOCATABLE_MEMBER:.*]] = llvm.getelementptr %[[LOAD_NESTED_DTYPE]][0, 2] : (!llvm.ptr) -> !llvm.ptr, [[REC_TY2:!llvm.struct<"_QFRecTy2", \(f32, array<10 x i32>, struct<\(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>\)>, i32\)>]]
+ %3 = fir.coordinate_of %2, %c2 : (!fir.ref<!fir.type<_QFRecTy2{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>, index) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ // CHECK: %[[GEP_NESTED_DTYPE_ALLOCATABLE_MEMBER_BADDR:.*]] = llvm.getelementptr %[[GEP_NESTED_DTYPE_ALLOCATABLE_MEMBER]][0, 0] : (!llvm.ptr) -> !llvm.ptr, [[DESC_TY2:!llvm.struct<\(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>\)>]]
+ %4 = fir.box_offset %3 base_addr : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>
+ // CHECK: %[[MAP_NESTED_MEMBER_BADDR:.*]] = omp.map.info var_ptr(%[[GEP_NESTED_DTYPE_ALLOCATABLE_MEMBER]] : !llvm.ptr, i32) var_ptr_ptr(%[[GEP_NESTED_DTYPE_ALLOCATABLE_MEMBER_BADDR]] : !llvm.ptr) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS]]) -> !llvm.ptr
+ %5 = omp.map.info var_ptr(%3 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.array<?xi32>) var_ptr_ptr(%4 : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) map_clauses(tofrom) capture(ByRef) bounds(%0) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>
+ // CHECK: %[[MAP_NESTED_MEMBER_DESC:.*]] = omp.map.info var_ptr(%[[GEP_NESTED_DTYPE_ALLOCATABLE_MEMBER]] : !llvm.ptr, [[DESC_TY2]]) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr
+ %6 = omp.map.info var_ptr(%3 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.box<!fir.heap<!fir.array<?xi32>>>) map_clauses(tofrom) capture(ByRef) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ // CHECK: "llvm.intr.memcpy"(%[[DTYPE_ALLOCATABLE_ALOCA_2]], %[[ARG_0]], {{.*}}) <{isVolatile = false}> : (!llvm.ptr, !llvm.ptr, i32) -> ()
+ // CHECK: %[[GEP_DTYPE_BADDR:.*]] = llvm.getelementptr %[[DTYPE_ALLOCATABLE_ALOCA_2]][0, 0] : (!llvm.ptr) -> !llvm.ptr, [[DESC_TY]]
+ // CHECK: %[[LOAD_GEP_DTYPE_BADDR:.*]] = llvm.load %[[GEP_DTYPE_BADDR]] : !llvm.ptr -> !llvm.ptr
+ %7 = fir.load %arg0 : !fir.ref<!fir.box<!fir.heap<!fir.type<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFRecTy2{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>>>
+ // CHECK: %[[LOAD_NESTED_DTYPE:.*]] = llvm.getelementptr %[[LOAD_GEP_DTYPE_BADDR]][0, 6] : (!llvm.ptr) -> !llvm.ptr, [[REC_TY]]
+ %8 = fir.coordinate_of %7, %c6 : (!fir.box<!fir.heap<!fir.type<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFRecTy2{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>>, index) -> !fir.ref<!fir.type<_QFRecTy2{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>
+ // CHECK: %[[NESTED_DTYPE_REGULAR_MEMBER_GEP:.*]] = llvm.getelementptr %[[LOAD_NESTED_DTYPE]][0, 3] : (!llvm.ptr) -> !llvm.ptr, [[REC_TY2]]
+ %9 = fir.coordinate_of %8, %c3 : (!fir.ref<!fir.type<_QFRecTy2{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>, index) -> !fir.ref<i32>
+ // CHECK: %[[MAP_REGULAR_NESTED_MEMBER:.*]] = omp.map.info var_ptr(%[[NESTED_DTYPE_REGULAR_MEMBER_GEP]] : !llvm.ptr, i32) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr
+ %10 = omp.map.info var_ptr(%9 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32>
+ // CHECK: %[[DTYPE_BADDR_GEP:.*]] = llvm.getelementptr %[[ARG_0]][0, 0] : (!llvm.ptr) -> !llvm.ptr, [[DESC_TY]]
+ %11 = fir.box_offset %arg0 base_addr : (!fir.ref<!fir.box<!fir.heap<!fir.type<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFRecTy2{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>>>) -> !fir.llvm_ptr<!fir.ref<!fir.type<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFRecTy2{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>>
+ // CHECK: %[[MAP_PARENT_BADDR:.*]] = omp.map.info var_ptr(%[[ARG_0]] : !llvm.ptr, [[REC_TY]]) var_ptr_ptr(%[[DTYPE_BADDR_GEP]] : !llvm.ptr) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr
+ %12 = omp.map.info var_ptr(%arg0 : !fir.ref<!fir.box<!fir.heap<!fir.type<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFRecTy2{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>>>, !fir.type<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFRecTy2{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>) var_ptr_ptr(%11 : !fir.llvm_ptr<!fir.ref<!fir.type<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFRecTy2{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>>) map_clauses(tofrom) capture(ByRef) -> !fir.llvm_ptr<!fir.ref<!fir.type<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFRecTy2{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>>
+ // CHECK: %[[MAP_PARENT_DESC:.*]] = omp.map.info var_ptr(%[[ARG_0]] : !llvm.ptr, [[DESC_TY]]) map_clauses(tofrom) capture(ByRef) members(%[[MAP_PARENT_BADDR]], %[[MAP_NESTED_MEMBER_DESC]], %[[MAP_NESTED_MEMBER_BADDR]], %[[MAP_REGULAR_NESTED_MEMBER]] : [0], [0, 6, 2], [0, 6, 2, 0], [0, 6, 3] : !llvm.ptr, !llvm.ptr, !llvm.ptr, !llvm.ptr) -> !llvm.ptr
+ %13 = omp.map.info var_ptr(%arg0 : !fir.ref<!fir.box<!fir.heap<!fir.type<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFRecTy2{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>>>, !fir.box<!fir.heap<!fir.type<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFRecTy2{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>>) map_clauses(tofrom) capture(ByRef) members(%12, %6, %5, %10 : [0], [0,6,2], [0,6,2,0], [0,6,3] : !fir.llvm_ptr<!fir.ref<!fir.type<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFRecTy2{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>>, !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<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFRecTy2{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>>>
+ // CHECK: omp.target map_entries(%[[MAP_PARENT_BADDR]] -> %[[ARG_1:.*]], %[[MAP_NESTED_MEMBER_DESC]] -> %[[ARG_2:.*]], %[[MAP_NESTED_MEMBER_BADDR]] -> %[[ARG_3:.*]], %[[MAP_REGULAR_NESTED_MEMBER]] -> %[[ARG_4:.*]], %[[MAP_PARENT_DESC]] -> %[[ARG_5:.*]] : !llvm.ptr, !llvm.ptr, !llvm.ptr, !llvm.ptr, !llvm.ptr) {
+ omp.target map_entries(%12 -> %arg1, %6 -> %arg2, %5 -> %arg3, %10 -> %arg4, %13 -> %arg5 : !fir.llvm_ptr<!fir.ref<!fir.type<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFRecTy2{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>>, !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<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFRecTy2{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>>>) {
+ omp.terminator
+ }
+ return
+}
+
+// -----
+
+// CHECK-LABEL: llvm.func @map_nested_dtype_alloca_mem2
+// CHECK-SAME: %[[ARG_0:.*]]: !llvm.ptr)
+func.func @map_nested_dtype_alloca_mem2(%arg0 : !fir.ref<!fir.type<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFRecTy2{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>) {
+ %c4 = arith.constant 4 : index
+ %c1 = arith.constant 1 : index
+ %c2 = arith.constant 2 : index
+ %c0 = arith.constant 0 : index
+ %c6 = arith.constant 6 : index
+ // CHECK: %[[BOUNDS:.*]] = omp.map.bounds lower_bound({{.*}}) upper_bound({{.*}}) extent({{.*}}) stride({{.*}}) start_idx({{.*}}) {stride_in_bytes = true}
+ %0 = omp.map.bounds lower_bound(%c0 : index) upper_bound(%c4 : index) extent(%c4 : index) stride(%c1 : index) start_idx(%c0 : index) {stride_in_bytes = true}
+ // CHECK: %[[NESTED_DTYPE_MEMBER_GEP:.*]] = llvm.getelementptr %[[ARG_0]][0, 6] : (!llvm.ptr) -> !llvm.ptr, [[REC_TY:!llvm.struct<"_QFRecTy", \(f32, struct<\(ptr, i64, i32, i8, i8, i8, i8\)>, array<10 x i32>, f32, struct<\(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>\)>, i32, struct<"_QFRecTy2", \(f32, array<10 x i32>, struct<\(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>\)>, i32\)>\)>]]
+ %1 = fir.coordinate_of %arg0, %c6 : (!fir.ref<!fir.type<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFRecTy2{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>, index) -> !fir.ref<!fir.type<_QFRecTy2{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>
+ // CHECK: %[[NESTED_ALLOCATABLE_MEMBER_GEP:.*]] = llvm.getelementptr %[[NESTED_DTYPE_MEMBER_GEP]][0, 2] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<"_QFRecTy2", (f32, array<10 x i32>, struct<(ptr, i64, i32, i8, i8, i8, i8, array<1 x array<3 x i64>>)>, i32)>
+ %2 = fir.coordinate_of %1, %c2 : (!fir.ref<!fir.type<_QFRecTy2{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>, index) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ // CHECK: %[[NESTED_ALLOCATABLE_MEMBER_BADDR_GEP:.*]] = llvm.getelementptr %[[NESTED_ALLOCATABLE_MEMBER_GEP]][0, 0] : (!llvm.ptr) -> !llvm.ptr, [[DESC_TY2]]
+ %3 = fir.box_offset %2 base_addr : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>
+ // CHECK: %[[MAP_NESTED_ALLOCATABLE_MEMBER_BADDR:.*]] = omp.map.info var_ptr(%[[NESTED_ALLOCATABLE_MEMBER_GEP]] : !llvm.ptr, i32) var_ptr_ptr(%[[NESTED_ALLOCATABLE_MEMBER_BADDR_GEP]] : !llvm.ptr) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS]]) -> !llvm.ptr
+ %4 = omp.map.info var_ptr(%2 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.array<?xi32>) var_ptr_ptr(%3 : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) map_clauses(tofrom) capture(ByRef) bounds(%0) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>
+ // CHECK: %[[MAP_NESTED_ALLOCATABLE_MEMBER_DESC:.*]] = omp.map.info var_ptr(%[[NESTED_ALLOCATABLE_MEMBER_GEP]] : !llvm.ptr, [[DESC_TY2]]) map_clauses(tofrom) capture(ByRef) -> !llvm.ptr
+ %5 = omp.map.info var_ptr(%2 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.box<!fir.heap<!fir.array<?xi32>>>) map_clauses(tofrom) capture(ByRef) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ // CHECK: %[[MAP_PARENT:.*]] = omp.map.info var_ptr(%[[ARG_0]] : !llvm.ptr, [[REC_TY]]) map_clauses(tofrom) capture(ByRef) members(%[[MAP_NESTED_ALLOCATABLE_MEMBER_DESC]], %[[MAP_NESTED_ALLOCATABLE_MEMBER_BADDR]] : [6, 2], [6, 2, 0] : !llvm.ptr, !llvm.ptr) -> !llvm.ptr {partial_map = true}
+ %6 = omp.map.info var_ptr(%arg0 : !fir.ref<!fir.type<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFRecTy2{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>, !fir.type<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFRecTy2{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>) map_clauses(tofrom) capture(ByRef) members(%5, %4 : [6,2], [6,2,0] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) -> !fir.ref<!fir.type<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFRecTy2{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>> {partial_map = true}
+ // CHECK: omp.target map_entries(%[[MAP_NESTED_ALLOCATABLE_MEMBER_DESC]] -> %[[ARG_1:.*]], %[[MAP_NESTED_ALLOCATABLE_MEMBER_BADDR]] -> %[[ARG_2:.*]], %[[MAP_PARENT]] -> %[[ARG_3:.*]] : !llvm.ptr, !llvm.ptr, !llvm.ptr) {
+ omp.target map_entries(%5 -> %arg1, %4 -> %arg2, %6 -> %arg3 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>, !fir.ref<!fir.type<_QFRecTy{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFRecTy2{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>) {
+ omp.terminator
+ }
+ return
+}
diff --git a/flang/test/Integration/OpenMP/map-types-and-sizes.f90 b/flang/test/Integration/OpenMP/map-types-and-sizes.f90
index 055fdecc914640..dac4938157a60d 100644
--- a/flang/test/Integration/OpenMP/map-types-and-sizes.f90
+++ b/flang/test/Integration/OpenMP/map-types-and-sizes.f90
@@ -30,8 +30,8 @@ subroutine mapType_array
!$omp end target
end subroutine mapType_array
-!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [3 x i64] [i64 0, i64 24, i64 4]
-!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [3 x i64] [i64 32, i64 281474976710657, i64 281474976711187]
+!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [4 x i64] [i64 0, i64 24, i64 8, i64 4]
+!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [4 x i64] [i64 32, i64 281474976711169, i64 281474976711171, i64 281474976711187]
subroutine mapType_ptr
integer, pointer :: a
!$omp target
@@ -39,8 +39,8 @@ subroutine mapType_ptr
!$omp end target
end subroutine mapType_ptr
-!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [3 x i64] [i64 0, i64 24, i64 4]
-!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [3 x i64] [i64 32, i64 281474976710657, i64 281474976711187]
+!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [4 x i64] [i64 0, i64 24, i64 8, i64 4]
+!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [4 x i64] [i64 32, i64 281474976711169, i64 281474976711171, i64 281474976711187]
subroutine mapType_allocatable
integer, allocatable :: a
allocate(a)
@@ -50,8 +50,8 @@ subroutine mapType_allocatable
deallocate(a)
end subroutine mapType_allocatable
-!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [3 x i64] [i64 0, i64 24, i64 4]
-!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [3 x i64] [i64 32, i64 281474976710657, i64 281474976710675]
+!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [4 x i64] [i64 0, i64 24, i64 8, i64 4]
+!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [4 x i64] [i64 32, i64 281474976710657, i64 281474976710659, i64 281474976710675]
subroutine mapType_ptr_explicit
integer, pointer :: a
!$omp target map(tofrom: a)
@@ -59,8 +59,8 @@ subroutine mapType_ptr_explicit
!$omp end target
end subroutine mapType_ptr_explicit
-!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [3 x i64] [i64 0, i64 24, i64 4]
-!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [3 x i64] [i64 32, i64 281474976710657, i64 281474976710675]
+!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [4 x i64] [i64 0, i64 24, i64 8, i64 4]
+!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [4 x i64] [i64 32, i64 281474976710657, i64 281474976710659, i64 281474976710675]
subroutine mapType_allocatable_explicit
integer, allocatable :: a
allocate(a)
@@ -69,7 +69,7 @@ subroutine mapType_allocatable_explicit
!$omp end target
deallocate(a)
end subroutine mapType_allocatable_explicit
-
+
!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [1 x i64] [i64 48]
!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [1 x i64] [i64 547]
subroutine mapType_derived_implicit
@@ -78,8 +78,8 @@ subroutine mapType_derived_implicit
integer(4) :: array(10)
integer(4) :: int
end type scalar_and_array
- type(scalar_and_array) :: scalar_arr
-
+ type(scalar_and_array) :: scalar_arr
+
!$omp target
scalar_arr%int = 1
!$omp end target
@@ -93,8 +93,8 @@ subroutine mapType_derived_explicit
integer(4) :: array(10)
integer(4) :: int
end type scalar_and_array
- type(scalar_and_array) :: scalar_arr
-
+ type(scalar_and_array) :: scalar_arr
+
!$omp target map(tofrom: scalar_arr)
scalar_arr%int = 1
!$omp end target
@@ -108,8 +108,8 @@ subroutine mapType_derived_explicit_single_member
integer(4) :: array(10)
integer(4) :: int
end type scalar_and_array
- type(scalar_and_array) :: scalar_arr
-
+ type(scalar_and_array) :: scalar_arr
+
!$omp target map(tofrom: scalar_arr%array)
scalar_arr%array(1) = 1
!$omp end target
@@ -123,8 +123,8 @@ subroutine mapType_derived_explicit_multiple_members
integer(4) :: array(10)
integer(4) :: int
end type scalar_and_array
- type(scalar_and_array) :: scalar_arr
-
+ type(scalar_and_array) :: scalar_arr
+
!$omp target map(tofrom: scalar_arr%int, scalar_arr%real)
scalar_arr%int = 1
!$omp end target
@@ -138,8 +138,8 @@ subroutine mapType_derived_explicit_member_with_bounds
integer(4) :: array(10)
integer(4) :: int
end type scalar_and_array
- type(scalar_and_array) :: scalar_arr
-
+ type(scalar_and_array) :: scalar_arr
+
!$omp target map(tofrom: scalar_arr%array(2:5))
scalar_arr%array(3) = 3
!$omp end target
@@ -160,8 +160,8 @@ subroutine mapType_derived_explicit_nested_single_member
type(nested) :: nest
integer(4) :: int
end type scalar_and_array
- type(scalar_and_array) :: scalar_arr
-
+ type(scalar_and_array) :: scalar_arr
+
!$omp target map(tofrom: scalar_arr%nest%real)
scalar_arr%nest%real = 1
!$omp end target
@@ -182,8 +182,8 @@ subroutine mapType_derived_explicit_multiple_nested_members
type(nested) :: nest
integer(4) :: int
end type scalar_and_array
- type(scalar_and_array) :: scalar_arr
-
+ type(scalar_and_array) :: scalar_arr
+
!$omp target map(tofrom: scalar_arr%nest%int, scalar_arr%nest%real)
scalar_arr%nest%int = 1
!$omp end target
@@ -204,13 +204,142 @@ subroutine mapType_derived_explicit_nested_member_with_bounds
type(nested) :: nest
integer(4) :: int
end type scalar_and_array
- type(scalar_and_array) :: scalar_arr
-
+ type(scalar_and_array) :: scalar_arr
+
!$omp target map(tofrom: scalar_arr%nest%array(2:5))
scalar_arr%nest%array(3) = 3
!$omp end target
end subroutine mapType_derived_explicit_nested_member_with_bounds
+!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [4 x i64] [i64 0, i64 48, i64 8, i64 0]
+!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [4 x i64] [i64 32, i64 281474976710657, i64 281474976710659, i64 281474976710675]
+subroutine mapType_derived_type_alloca()
+ type :: one_layer
+ real(4) :: i
+ integer, allocatable :: scalar
+ integer(4) :: array_i(10)
+ real(4) :: j
+ integer, allocatable :: array_j(:)
+ integer(4) :: k
+ end type one_layer
+
+ type(one_layer) :: one_l
+
+ allocate(one_l%array_j(10))
+
+ !$omp target map(tofrom: one_l%array_j)
+ one_l%array_j(1) = 10
+ !$omp end target
+end subroutine
+
+!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [8 x i64] [i64 0, i64 40, i64 8, i64 136, i64 48, i64 8, i64 0, i64 4]
+!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [8 x i64] [i64 32, i64 281474976710657, i64 281474976710659, i64 281474976710675, i64 281474976710657, i64 281474976710659, i64 281474976710675, i64 281474976710659]
+subroutine mapType_alloca_derived_type()
+ type :: one_layer
+ real(4) :: i
+ integer, allocatable :: scalar
+ integer(4) :: array_i(10)
+ real(4) :: j
+ integer, allocatable :: array_j(:)
+ integer(4) :: k
+ end type one_layer
+
+ type(one_layer), allocatable :: one_l
+
+ allocate(one_l)
+ allocate(one_l%array_j(10))
+
+ !$omp target map(tofrom: one_l%array_j, one_l%k)
+ one_l%array_j(1) = 10
+ one_l%k = 20
+ !$omp end target
+end subroutine
+
+!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [8 x i64] [i64 0, i64 40, i64 8, i64 240, i64 48, i64 8, i64 0, i64 4]
+!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [8 x i64] [i64 32, i64 281474976710657, i64 281474976710659, i64 281474976710675, i64 281474976710657, i64 281474976710659, i64 281474976710675, i64 281474976710659]
+subroutine mapType_alloca_nested_derived_type()
+ type :: middle_layer
+ real(4) :: i
+ integer(4) :: array_i(10)
+ integer, allocatable :: array_k(:)
+ integer(4) :: k
+ end type middle_layer
+
+ type :: top_layer
+ real(4) :: i
+ integer, allocatable :: scalar
+ integer(4) :: array_i(10)
+ real(4) :: j
+ integer, allocatable :: array_j(:)
+ integer(4) :: k
+ type(middle_layer) :: nest
+ end type top_layer
+
+ type(top_layer), allocatable :: one_l
+
+ allocate(one_l)
+ allocate(one_l%nest%array_k(10))
+
+ !$omp target map(tofrom: one_l%nest%array_k, one_l%nest%k)
+ one_l%nest%array_k(1) = 10
+ one_l%nest%k = 20
+ !$omp end target
+end subroutine
+
+!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [4 x i64] [i64 0, i64 48, i64 8, i64 0]
+!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [4 x i64] [i64 32, i64 281474976710657, i64 281474976710659, i64 281474976710675]
+subroutine mapType_nested_derived_type_alloca()
+ type :: middle_layer
+ real(4) :: i
+ integer(4) :: array_i(10)
+ integer, allocatable :: array_k(:)
+ integer(4) :: k
+ end type middle_layer
+
+ type :: top_layer
+ real(4) :: i
+ integer, allocatable :: scalar
+ integer(4) :: array_i(10)
+ real(4) :: j
+ integer, allocatable :: array_j(:)
+ integer(4) :: k
+ type(middle_layer) :: nest
+ end type top_layer
+
+ type(top_layer) :: one_l
+
+ allocate(one_l%nest%array_k(10))
+
+ !$omp target map(tofrom: one_l%nest%array_k)
+ one_l%nest%array_k(1) = 25
+ !$omp end target
+end subroutine
+
+!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [7 x i64] [i64 0, i64 64, i64 8, i64 0, i64 48, i64 8, i64 0]
+!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [7 x i64] [i64 32, i64 281474976710657, i64 281474976710656, i64 281474976710672, i64 281474976710657, i64 281474976710659, i64 281474976710675]
+subroutine mapType_nested_derived_type_member_idx()
+type :: vertexes
+ integer :: test
+ integer(4), allocatable :: vertexx(:)
+ integer(4), allocatable :: vertexy(:)
+end type vertexes
+
+type :: dtype
+ real(4) :: i
+ type(vertexes), allocatable :: vertexes(:)
+ integer(4) :: array_i(10)
+end type dtype
+
+type(dtype) :: alloca_dtype
+
+allocate(alloca_dtype%vertexes(4))
+allocate(alloca_dtype%vertexes(2)%vertexy(10))
+
+!$omp target map(tofrom: alloca_dtype%vertexes(2)%vertexy)
+ alloca_dtype%vertexes(2)%vertexy(5) = 20
+!$omp end target
+end subroutine
+
!CHECK: @.offload_sizes{{.*}} = private unnamed_addr constant [2 x i64] [i64 8, i64 4]
!CHECK: @.offload_maptypes{{.*}} = private unnamed_addr constant [2 x i64] [i64 544, i64 800]
subroutine mapType_c_ptr
@@ -263,7 +392,7 @@ end subroutine mapType_common_block_members
!CHECK: %[[ALLOCA_INT:.*]] = ptrtoint ptr %[[ALLOCA]] to i64
!CHECK: %[[SIZE_DIFF:.*]] = sub i64 %[[ALLOCA_GEP_INT]], %[[ALLOCA_INT]]
!CHECK: %[[DIV:.*]] = sdiv exact i64 %[[SIZE_DIFF]], ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64)
-!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [3 x i64], ptr %.offload_sizes, i32 0, i32 0
+!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [4 x i64], ptr %.offload_sizes, i32 0, i32 0
!CHECK: store i64 %[[DIV]], ptr %[[OFFLOAD_SIZE_ARR]], align 8
!CHECK-LABEL: define {{.*}} @{{.*}}maptype_allocatable_explicit_{{.*}}
@@ -273,7 +402,7 @@ end subroutine mapType_common_block_members
!CHECK: %[[ALLOCA_INT:.*]] = ptrtoint ptr %[[ALLOCA]] to i64
!CHECK: %[[SIZE_DIFF:.*]] = sub i64 %[[ALLOCA_GEP_INT]], %[[ALLOCA_INT]]
!CHECK: %[[DIV:.*]] = sdiv exact i64 %[[SIZE_DIFF]], ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64)
-!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [3 x i64], ptr %.offload_sizes, i32 0, i32 0
+!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [4 x i64], ptr %.offload_sizes, i32 0, i32 0
!CHECK: store i64 %[[DIV]], ptr %[[OFFLOAD_SIZE_ARR]], align 8
!CHECK-LABEL: define {{.*}} @{{.*}}maptype_derived_implicit_{{.*}}
@@ -372,6 +501,294 @@ end subroutine mapType_common_block_members
!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [1 x ptr], ptr %.offload_ptrs, i32 0, i32 0
!CHECK: store ptr %[[ARR_OFF]], ptr %[[OFFLOAD_PTR_ARR]], align 8
+!CHECK-LABEL: define {{.*}} @{{.*}}maptype_derived_type_alloca_{{.*}}
+!CHECK: %[[ALLOCATABLE_DESC_ALLOCA:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, align 8
+!CHECK: %[[ALLOCA:.*]] = alloca %_QFmaptype_derived_type_allocaTone_layer, i64 1, align 8
+!CHECK: %[[DESC_BOUND_ACCESS:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[ALLOCATABLE_DESC_ALLOCA]], i32 0, i32 7, i64 0, i32 1
+!CHECK: %[[DESC_BOUND_ACCESS_LOAD:.*]] = load i64, ptr %[[DESC_BOUND_ACCESS]], align 8
+!CHECK: %[[OFFSET_UB:.*]] = sub i64 %[[DESC_BOUND_ACCESS_LOAD]], 1
+!CHECK: %[[MEMBER_ACCESS:.*]] = getelementptr %_QFmaptype_derived_type_allocaTone_layer, ptr %[[ALLOCA]], i32 0, i32 4
+!CHECK: %[[MEMBER_DESCRIPTOR_BASE_ADDR:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[MEMBER_ACCESS]], i32 0, i32 0
+!CHECK: %[[CALCULATE_DIM_SIZE:.*]] = sub i64 %[[OFFSET_UB]], 0
+!CHECK: %[[RESTORE_OFFSET:.*]] = add i64 %[[CALCULATE_DIM_SIZE]], 1
+!CHECK: %[[MEMBER_BASE_ADDR_SIZE:.*]] = mul i64 1, %[[RESTORE_OFFSET]]
+!CHECK: %[[DESC_BASE_ADDR_DATA_SIZE:.*]] = mul i64 %[[MEMBER_BASE_ADDR_SIZE]], 4
+!CHECK: %[[MEMBER_ACCESS_ADDR_END:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[MEMBER_ACCESS]], i64 1
+!CHECK: %[[MEMBER_ACCESS_ADDR_INT:.*]] = ptrtoint ptr %[[MEMBER_ACCESS_ADDR_END]] to i64
+!CHECK: %[[MEMBER_ACCESS_ADDR_BEGIN:.*]] = ptrtoint ptr %[[MEMBER_ACCESS]] to i64
+!CHECK: %[[DTYPE_SEGMENT_SIZE:.*]] = sub i64 %[[MEMBER_ACCESS_ADDR_INT]], %[[MEMBER_ACCESS_ADDR_BEGIN]]
+!CHECK: %[[DTYPE_SIZE_CALC:.*]] = sdiv exact i64 %[[DTYPE_SEGMENT_SIZE]], ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64)
+!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_baseptrs, i32 0, i32 0
+!CHECK: store ptr %[[ALLOCA]], ptr %[[BASE_PTR_ARR]], align 8
+!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_ptrs, i32 0, i32 0
+!CHECK: store ptr %[[MEMBER_ACCESS]], ptr %[[OFFLOAD_PTR_ARR]], align 8
+!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [4 x i64], ptr %.offload_sizes, i32 0, i32 0
+!CHECK: store i64 %[[DTYPE_SIZE_CALC]], ptr %[[OFFLOAD_SIZE_ARR]], align 8
+!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_baseptrs, i32 0, i32 1
+!CHECK: store ptr %[[ALLOCA]], ptr %[[BASE_PTR_ARR]], align 8
+!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_ptrs, i32 0, i32 1
+!CHECK: store ptr %[[MEMBER_ACCESS]], ptr %[[OFFLOAD_PTR_ARR]], align 8
+!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_baseptrs, i32 0, i32 2
+!CHECK: store ptr %[[ALLOCA]], ptr %[[BASE_PTR_ARR]], align 8
+!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_ptrs, i32 0, i32 2
+!CHECK: store ptr %[[MEMBER_DESCRIPTOR_BASE_ADDR]], ptr %[[OFFLOAD_PTR_ARR]], align 8
+!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_baseptrs, i32 0, i32 3
+!CHECK: store ptr %[[MEMBER_DESCRIPTOR_BASE_ADDR]], ptr %[[BASE_PTR_ARR]], align 8
+!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_ptrs, i32 0, i32 3
+!CHECK: store ptr %array_offset, ptr %[[OFFLOAD_PTR_ARR]], align 8
+!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [4 x i64], ptr %.offload_sizes, i32 0, i32 3
+!CHECK: store i64 %[[DESC_BASE_ADDR_DATA_SIZE]], ptr %[[OFFLOAD_SIZE_ARR]], align 8
+
+!CHECK-LABEL: define {{.*}} @{{.*}}maptype_alloca_derived_type_{{.*}}
+!CHECK: %{{.*}} = alloca { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, align 8
+!CHECK: %[[DTYPE_DESC_ALLOCA:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, align 8
+!CHECK: %[[DTYPE_ARRAY_MEMBER_DESC_ALLOCA:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, align 8
+!CHECK: %[[DTYPE_DESC_ALLOCA_2:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, align 8
+!CHECK: %[[DTYPE_DESC_ALLOCA_3:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, i64 1, align 8
+!CHECK: %[[ACCESS_DESC_MEMBER_UB:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[DTYPE_ARRAY_MEMBER_DESC_ALLOCA]], i32 0, i32 7, i64 0, i32 1
+!CHECK: %[[LOAD_DESC_MEMBER_UB:.*]] = load i64, ptr %[[ACCESS_DESC_MEMBER_UB]], align 8
+!CHECK: %[[OFFSET_MEMBER_UB:.*]] = sub i64 %[[LOAD_DESC_MEMBER_UB]], 1
+!CHECK: %[[DTYPE_BASE_ADDR_ACCESS:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[DTYPE_DESC_ALLOCA_2]], i32 0, i32 0
+!CHECK: %[[DTYPE_BASE_ADDR_LOAD:.*]] = load ptr, ptr %[[DTYPE_BASE_ADDR_ACCESS]], align 8
+!CHECK: %[[DTYPE_ALLOCA_MEMBER_ACCESS:.*]] = getelementptr %_QFmaptype_alloca_derived_typeTone_layer, ptr %[[DTYPE_BASE_ADDR_LOAD]], i32 0, i32 4
+!CHECK: %[[DTYPE_ALLOCA_MEMBER_BASE_ADDR_ACCESS:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[DTYPE_ALLOCA_MEMBER_ACCESS]], i32 0, i32 0
+!CHECK: %[[DTYPE_BASE_ADDR_ACCESS_2:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[DTYPE_DESC_ALLOCA]], i32 0, i32 0
+!CHECK: %[[DTYPE_BASE_ADDR_LOAD_2:.*]] = load ptr, ptr %[[DTYPE_BASE_ADDR_ACCESS_2]], align 8
+!CHECK: %[[DTYPE_NONALLOCA_MEMBER_ACCESS:.*]] = getelementptr %_QFmaptype_alloca_derived_typeTone_layer, ptr %[[DTYPE_BASE_ADDR_LOAD_2]], i32 0, i32 5
+!CHECK: %[[DTYPE_BASE_ADDR_ACCESS_3:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[DTYPE_DESC_ALLOCA_3]], i32 0, i32 0
+!CHECK: %[[MEMBER_SIZE_CALC_1:.*]] = sub i64 %[[OFFSET_MEMBER_UB]], 0
+!CHECK: %[[MEMBER_SIZE_CALC_2:.*]] = add i64 %[[MEMBER_SIZE_CALC_1]], 1
+!CHECK: %[[MEMBER_SIZE_CALC_3:.*]] = mul i64 1, %[[MEMBER_SIZE_CALC_2]]
+!CHECK: %[[MEMBER_SIZE_CALC_4:.*]] = mul i64 %[[MEMBER_SIZE_CALC_3]], 4
+!CHECK: %[[DTYPE_BASE_ADDR_LOAD_3:.*]] = load ptr, ptr %[[DTYPE_BASE_ADDR_ACCESS_3]], align 8
+!CHECK: %[[LOAD_DTYPE_DESC_MEMBER:.*]] = load ptr, ptr %[[DTYPE_ALLOCA_MEMBER_BASE_ADDR_ACCESS]], align 8
+!CHECK: %[[MEMBER_ARRAY_OFFSET:.*]] = getelementptr inbounds i32, ptr %[[LOAD_DTYPE_DESC_MEMBER]], i64 0
+!CHECK: %[[DTYPE_END_OFFSET:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[DTYPE_DESC_ALLOCA_3]], i32 1
+!CHECK: %[[DTYPE_END:.*]] = ptrtoint ptr %[[DTYPE_END_OFFSET]] to i64
+!CHECK: %[[DTYPE_BEGIN:.*]] = ptrtoint ptr %[[DTYPE_DESC_ALLOCA_3]] to i64
+!CHECK: %[[DTYPE_DESC_SZ_CALC:.*]] = sub i64 %[[DTYPE_END]], %[[DTYPE_BEGIN]]
+!CHECK: %[[DTYPE_DESC_SZ:.*]] = sdiv exact i64 %[[DTYPE_DESC_SZ_CALC]], ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64)
+!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 0
+!CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[BASE_PTR_ARR]], align 8
+!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 0
+!CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[OFFLOAD_PTR_ARR]], align 8
+!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [8 x i64], ptr %.offload_sizes, i32 0, i32 0
+!CHECK: store i64 %[[DTYPE_DESC_SZ]], ptr %[[OFFLOAD_SIZE_ARR]], align 8
+!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 1
+!CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[BASE_PTR_ARR]], align 8
+!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 1
+!CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[OFFLOAD_PTR_ARR]], align 8
+!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 2
+!CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[BASE_PTR_ARR]], align 8
+!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 2
+!CHECK: store ptr %[[DTYPE_BASE_ADDR_ACCESS_3]], ptr %[[OFFLOAD_PTR_ARR]], align 8
+!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 3
+!CHECK: store ptr %[[DTYPE_BASE_ADDR_ACCESS_3]], ptr %[[BASE_PTR_ARR]], align 8
+!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 3
+!CHECK: store ptr %[[DTYPE_BASE_ADDR_LOAD_3]], ptr %[[OFFLOAD_PTR_ARR]], align 8
+!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 4
+!CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[BASE_PTR_ARR]], align 8
+!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 4
+!CHECK: store ptr %[[DTYPE_ALLOCA_MEMBER_ACCESS]], ptr %[[OFFLOAD_PTR_ARR]], align 8
+!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 5
+!CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[BASE_PTR_ARR]], align 8
+!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 5
+!CHECK: store ptr %[[DTYPE_ALLOCA_MEMBER_BASE_ADDR_ACCESS]], ptr %[[OFFLOAD_PTR_ARR]], align 8
+!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 6
+!CHECK: store ptr %[[DTYPE_ALLOCA_MEMBER_BASE_ADDR_ACCESS]], ptr %[[BASE_PTR_ARR]], align 8
+!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 6
+!CHECK: store ptr %[[MEMBER_ARRAY_OFFSET]], ptr %[[OFFLOAD_PTR_ARR]], align 8
+!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [8 x i64], ptr %.offload_sizes, i32 0, i32 6
+!CHECK: store i64 %[[MEMBER_SIZE_CALC_4]], ptr %[[OFFLOAD_SIZE_ARR]], align 8
+!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 7
+!CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[BASE_PTR_ARR]], align 8
+!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 7
+!CHECK: store ptr %[[DTYPE_NONALLOCA_MEMBER_ACCESS]], ptr %[[OFFLOAD_PTR_ARR]], align 8
+
+!CHECK-LABEL: define {{.*}} @{{.*}}maptype_alloca_nested_derived_type{{.*}}
+!CHECK: %{{.*}} = alloca { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, align 8
+!CHECK: %[[DTYPE_DESC_ALLOCA_1:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, align 8
+!CHECK: %[[ALLOCATABLE_MEMBER_ALLOCA:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, align 8
+!CHECK: %[[DTYPE_DESC_ALLOCA_2:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, align 8
+!CHECK: %[[DTYPE_DESC_ALLOCA_3:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, i64 1, align 8
+!CHECK: %[[ALLOCATABLE_MEMBER_ALLOCA_UB:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[ALLOCATABLE_MEMBER_ALLOCA]], i32 0, i32 7, i64 0, i32 1
+!CHECK: %[[ALLOCATABLE_MEMBER_ALLOCA_UB_LOAD:.*]] = load i64, ptr %[[ALLOCATABLE_MEMBER_ALLOCA_UB]], align 8
+!CHECK: %[[ALLOCATABLE_MEMBER_SIZE_CALC_1:.*]] = sub i64 %[[ALLOCATABLE_MEMBER_ALLOCA_UB_LOAD]], 1
+!CHECK: %[[DTYPE_DESC_BASE_ADDR_ACCESS:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[DTYPE_DESC_ALLOCA_2]], i32 0, i32 0
+!CHECK: %[[DTYPE_DESC_BASE_ADDR_LOAD:.*]] = load ptr, ptr %[[DTYPE_DESC_BASE_ADDR_ACCESS]], align 8
+!CHECK: %[[NESTED_DTYPE_ACCESS:.*]] = getelementptr %_QFmaptype_alloca_nested_derived_typeTtop_layer, ptr %[[DTYPE_DESC_BASE_ADDR_LOAD]], i32 0, i32 6
+!CHECK: %[[MAPPED_MEMBER_ACCESS:.*]] = getelementptr %_QFmaptype_alloca_nested_derived_typeTmiddle_layer, ptr %[[NESTED_DTYPE_ACCESS]], i32 0, i32 2
+!CHECK: %[[MAPPED_MEMBER_BASE_ADDR_ACCESS:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[MAPPED_MEMBER_ACCESS]], i32 0, i32 0
+!CHECK: %[[DTYPE_DESC_BASE_ADDR_ACCESS_2:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[DTYPE_DESC_ALLOCA_1]], i32 0, i32 0
+!CHECK: %[[DTYPE_DESC_BASE_ADDR_LOAD_2:.*]] = load ptr, ptr %[[DTYPE_DESC_BASE_ADDR_ACCESS_2]], align 8
+!CHECK: %[[NESTED_DTYPE_ACCESS:.*]] = getelementptr %_QFmaptype_alloca_nested_derived_typeTtop_layer, ptr %[[DTYPE_DESC_BASE_ADDR_LOAD_2]], i32 0, i32 6
+!CHECK: %[[NESTED_NONALLOCA_MEMBER_ACCESS:.*]] = getelementptr %_QFmaptype_alloca_nested_derived_typeTmiddle_layer, ptr %[[NESTED_DTYPE_ACCESS]], i32 0, i32 3
+!CHECK: %[[DTYPE_DESC_BASE_ADDR:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[DTYPE_DESC_ALLOCA_3]], i32 0, i32 0
+!CHECK: %[[ALLOCATABLE_MEMBER_SIZE_CALC_2:.*]] = sub i64 %[[ALLOCATABLE_MEMBER_SIZE_CALC_1]], 0
+!CHECK: %[[ALLOCATABLE_MEMBER_SIZE_CALC_3:.*]] = add i64 %[[ALLOCATABLE_MEMBER_SIZE_CALC_2]], 1
+!CHECK: %[[ALLOCATABLE_MEMBER_SIZE_CALC_4:.*]] = mul i64 1, %[[ALLOCATABLE_MEMBER_SIZE_CALC_3]]
+!CHECK: %[[ALLOCATABLE_MEMBER_SIZE_CALC_5:.*]] = mul i64 %[[ALLOCATABLE_MEMBER_SIZE_CALC_4]], 4
+!CHECK: %[[LOAD_BASE_ADDR:.*]] = load ptr, ptr %[[DTYPE_DESC_BASE_ADDR]], align 8
+!CHECK: %[[LOAD_DESC_MEMBER_BASE_ADDR:.*]] = load ptr, ptr %[[MAPPED_MEMBER_BASE_ADDR_ACCESS]], align 8
+!CHECK: %[[ARRAY_OFFSET:.*]] = getelementptr inbounds i32, ptr %[[LOAD_DESC_MEMBER_BASE_ADDR]], i64 0
+!CHECK: %[[DTYPE_DESC_SIZE_CALC_1:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[DTYPE_DESC_ALLOCA_3]], i32 1
+!CHECK: %[[DTYPE_DESC_SIZE_CALC_2:.*]] = ptrtoint ptr %[[DTYPE_DESC_SIZE_CALC_1]] to i64
+!CHECK: %[[DTYPE_DESC_SIZE_CALC_3:.*]] = ptrtoint ptr %[[DTYPE_DESC_ALLOCA_3]] to i64
+!CHECK: %[[DTYPE_DESC_SIZE_CALC_4:.*]] = sub i64 %[[DTYPE_DESC_SIZE_CALC_2]], %[[DTYPE_DESC_SIZE_CALC_3]]
+!CHECK: %[[DTYPE_DESC_SIZE_CALC_5:.*]] = sdiv exact i64 %[[DTYPE_DESC_SIZE_CALC_4]], ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64)
+!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 0
+!CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[BASE_PTR_ARR]], align 8
+!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 0
+!CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[OFFLOAD_PTR_ARR]], align 8
+!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [8 x i64], ptr %.offload_sizes, i32 0, i32 0
+!CHECK: store i64 %[[DTYPE_DESC_SIZE_CALC_5]], ptr %[[OFFLOAD_SIZE_ARR]], align 8
+!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 1
+!CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[BASE_PTR_ARR]], align 8
+!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 1
+!CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[OFFLOAD_PTR_ARR]], align 8
+!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 2
+!CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[BASE_PTR_ARR]], align 8
+!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 2
+!CHECK: store ptr %[[DTYPE_DESC_BASE_ADDR]], ptr %[[OFFLOAD_PTR_ARR]], align 8
+!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 3
+!CHECK: store ptr %[[DTYPE_DESC_BASE_ADDR]], ptr %[[BASE_PTR_ARR]], align 8
+!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 3
+!CHECK: store ptr %[[LOAD_BASE_ADDR]], ptr %[[OFFLOAD_PTR_ARR]], align 8
+!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 4
+!CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[BASE_PTR_ARR]], align 8
+!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 4
+!CHECK: store ptr %[[MAPPED_MEMBER_ACCESS]], ptr %[[OFFLOAD_PTR_ARR]], align 8
+!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 5
+!CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[BASE_PTR_ARR]], align 8
+!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 5
+!CHECK: store ptr %[[MAPPED_MEMBER_BASE_ADDR_ACCESS]], ptr %[[OFFLOAD_PTR_ARR]], align 8
+!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 6
+!CHECK: store ptr %[[MAPPED_MEMBER_BASE_ADDR_ACCESS]], ptr %[[BASE_PTR_ARR]], align 8
+!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 6
+!CHECK: store ptr %[[ARRAY_OFFSET]], ptr %[[OFFLOAD_PTR_ARR]], align 8
+!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [8 x i64], ptr %.offload_sizes, i32 0, i32 6
+!CHECK: store i64 %[[ALLOCATABLE_MEMBER_SIZE_CALC_5]], ptr %[[OFFLOAD_SIZE_ARR]], align 8
+!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_baseptrs, i32 0, i32 7
+!CHECK: store ptr %[[DTYPE_DESC_ALLOCA_3]], ptr %[[BASE_PTR_ARR]], align 8
+!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [8 x ptr], ptr %.offload_ptrs, i32 0, i32 7
+!CHECK: store ptr %[[NESTED_NONALLOCA_MEMBER_ACCESS]], ptr %[[OFFLOAD_PTR_ARR]], align 8
+
+!CHECK-LABEL: define {{.*}} @{{.*}}maptype_nested_derived_type_alloca{{.*}}
+!CHECK: %[[ALLOCATABLE_MEMBER_ALLOCA:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, align 8
+!CHECK: %[[ALLOCA:.*]] = alloca %_QFmaptype_nested_derived_type_allocaTtop_layer, i64 1, align 8
+!CHECK: %[[ALLOCATABLE_MEMBER_BASE_ADDR:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[ALLOCATABLE_MEMBER_ALLOCA]], i32 0, i32 7, i64 0, i32 1
+!CHECK: %[[ALLOCATABLE_MEMBER_ADDR_LOAD:.*]] = load i64, ptr %[[ALLOCATABLE_MEMBER_BASE_ADDR]], align 8
+!CHECK: %[[ALLOCATABLE_MEMBER_SIZE_CALC_1:.*]] = sub i64 %[[ALLOCATABLE_MEMBER_ADDR_LOAD]], 1
+!CHECK: %[[NESTED_DTYPE_MEMBER_ACCESS:.*]] = getelementptr %_QFmaptype_nested_derived_type_allocaTtop_layer, ptr %[[ALLOCA]], i32 0, i32 6
+!CHECK: %[[NESTED_MEMBER_ACCESS:.*]] = getelementptr %_QFmaptype_nested_derived_type_allocaTmiddle_layer, ptr %[[NESTED_DTYPE_MEMBER_ACCESS]], i32 0, i32 2
+!CHECK: %[[NESTED_MEMBER_BASE_ADDR_ACCESS:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %{{.*}}, i32 0, i32 0
+!CHECK: %[[ALLOCATABLE_MEMBER_SIZE_CALC_2:.*]] = sub i64 %[[ALLOCATABLE_MEMBER_SIZE_CALC_1]], 0
+!CHECK: %[[ALLOCATABLE_MEMBER_SIZE_CALC_3:.*]] = add i64 %[[ALLOCATABLE_MEMBER_SIZE_CALC_2]], 1
+!CHECK: %[[ALLOCATABLE_MEMBER_SIZE_CALC_4:.*]] = mul i64 1, %[[ALLOCATABLE_MEMBER_SIZE_CALC_3]]
+!CHECK: %[[ALLOCATABLE_MEMBER_SIZE_CALC_5:.*]] = mul i64 %[[ALLOCATABLE_MEMBER_SIZE_CALC_4]], 4
+!CHECK: %[[LOAD_BASE_ADDR:.*]] = load ptr, ptr %[[NESTED_MEMBER_BASE_ADDR_ACCESS]], align 8
+!CHECK: %[[ARR_OFFS:.*]] = getelementptr inbounds i32, ptr %[[LOAD_BASE_ADDR]], i64 0
+!CHECK: %[[NESTED_MEMBER_BASE_ADDR_ACCESS_2:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[NESTED_MEMBER_ACCESS]], i64 1
+!CHECK: %[[DTYPE_SEGMENT_SIZE_CALC_1:.*]] = ptrtoint ptr %[[NESTED_MEMBER_BASE_ADDR_ACCESS_2]] to i64
+!CHECK: %[[DTYPE_SEGMENT_SIZE_CALC_2:.*]] = ptrtoint ptr %[[NESTED_MEMBER_ACCESS]] to i64
+!CHECK: %[[DTYPE_SEGMENT_SIZE_CALC_3:.*]] = sub i64 %[[DTYPE_SEGMENT_SIZE_CALC_1]], %[[DTYPE_SEGMENT_SIZE_CALC_2]]
+!CHECK: %[[DTYPE_SEGMENT_SIZE_CALC_4:.*]] = sdiv exact i64 %[[DTYPE_SEGMENT_SIZE_CALC_3]], ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64)
+!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_baseptrs, i32 0, i32 0
+!CHECK: store ptr %[[ALLOCA]], ptr %[[BASE_PTR_ARR]], align 8
+!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_ptrs, i32 0, i32 0
+!CHECK: store ptr %[[NESTED_MEMBER_ACCESS]], ptr %[[OFFLOAD_PTR_ARR]], align 8
+!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [4 x i64], ptr %.offload_sizes, i32 0, i32 0
+!CHECK: store i64 %[[DTYPE_SEGMENT_SIZE_CALC_4]], ptr %[[OFFLOAD_SIZE_ARR]], align 8
+!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_baseptrs, i32 0, i32 1
+!CHECK: store ptr %[[ALLOCA]], ptr %[[BASE_PTR_ARR]], align 8
+!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_ptrs, i32 0, i32 1
+!CHECK: store ptr %[[NESTED_MEMBER_ACCESS]], ptr %[[OFFLOAD_PTR_ARR]], align 8
+!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_baseptrs, i32 0, i32 2
+!CHECK: store ptr %[[ALLOCA]], ptr %[[BASE_PTR_ARR]], align 8
+!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_ptrs, i32 0, i32 2
+!CHECK: store ptr %[[NESTED_MEMBER_BASE_ADDR_ACCESS]], ptr %[[OFFLOAD_PTR_ARR]], align 8
+!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_baseptrs, i32 0, i32 3
+!CHECK: store ptr %[[NESTED_MEMBER_BASE_ADDR_ACCESS]], ptr %[[BASE_PTR_ARR]], align 8
+!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [4 x ptr], ptr %.offload_ptrs, i32 0, i32 3
+!CHECK: store ptr %[[ARR_OFFS]], ptr %[[OFFLOAD_PTR_ARR]], align 8
+!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [4 x i64], ptr %.offload_sizes, i32 0, i32 3
+!CHECK: store i64 %[[ALLOCATABLE_MEMBER_SIZE_CALC_5]], ptr %[[OFFLOAD_SIZE_ARR]], align 8
+
+!CHECK-LABEL: define {{.*}} @{{.*}}maptype_nested_derived_type_member_idx{{.*}}
+!CHECK: %[[ALLOCA_0:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] }, align 8
+!CHECK: %[[ALLOCA_1:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, align 8
+!CHECK: %[[ALLOCA:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] }, align 8
+!CHECK: %[[BASE_PTR_1:.*]] = alloca %_QFmaptype_nested_derived_type_member_idxTdtype, i64 1, align 8
+!CHECK: %{{.*}} = getelementptr %_QFmaptype_nested_derived_type_member_idxTdtype, ptr %[[BASE_PTR_1]], i32 0, i32 1
+!CHECK: %[[BOUNDS_ACC:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] }, ptr %[[ALLOCA]], i32 0, i32 7, i64 0, i32 1
+!CHECK: %[[BOUNDS_LD:.*]] = load i64, ptr %[[BOUNDS_ACC]], align 8
+!CHECK: %[[BOUNDS_ACC_2:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[ALLOCA_1]], i32 0, i32 7, i64 0, i32 1
+!CHECK: %[[BOUNDS_LD_2:.*]] = load i64, ptr %[[BOUNDS_ACC_2]], align 8
+!CHECK: %[[BOUNDS_CALC:.*]] = sub i64 %[[BOUNDS_LD_2]], 1
+!CHECK: %[[OFF_PTR_1:.*]] = getelementptr %_QFmaptype_nested_derived_type_member_idxTdtype, ptr %[[BASE_PTR_1]], i32 0, i32 1
+!CHECK: %[[OFF_PTR_CALC_0:.*]] = sub i64 %[[BOUNDS_LD]], 1
+!CHECK: %[[OFF_PTR_2:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] }, ptr %[[OFF_PTR_1]], i32 0, i32 0
+!CHECK: %[[GEP_DESC_PTR:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] }, ptr %[[ALLOCA_0]], i32 0, i32 0
+!CHECK: %[[LOAD_DESC_PTR:.*]] = load ptr, ptr %[[GEP_DESC_PTR]], align 8
+!CHECK: %[[SZ_CALC_1:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] }, ptr %[[ALLOCA_0]], i32 0, i32 7, i32 0, i32 2
+!CHECK: %[[SZ_CALC_2:.*]] = load i64, ptr %[[SZ_CALC_1]], align 8
+!CHECK: %[[SZ_CALC_3:.*]] = mul nsw i64 1, %[[SZ_CALC_2]]
+!CHECK: %[[SZ_CALC_4:.*]] = add nsw i64 %[[SZ_CALC_3]], 0
+!CHECK: %[[SZ_CALC_5:.*]] = getelementptr i8, ptr %[[LOAD_DESC_PTR]], i64 %[[SZ_CALC_4]]
+!CHECK: %[[SZ_CALC_6:.*]] = getelementptr %_QFmaptype_nested_derived_type_member_idxTvertexes, ptr %[[SZ_CALC_5]], i32 0, i32 2
+!CHECK: %[[OFF_PTR_4:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[SZ_CALC_6]], i32 0, i32 0
+!CHECK: %[[OFF_PTR_CALC_1:.*]] = sub i64 %[[OFF_PTR_CALC_0]], 0
+!CHECK: %[[OFF_PTR_CALC_2:.*]] = add i64 %[[OFF_PTR_CALC_1]], 1
+!CHECK: %[[OFF_PTR_CALC_3:.*]] = mul i64 1, %[[OFF_PTR_CALC_2]]
+!CHECK: %[[OFF_PTR_3:.*]] = mul i64 %[[OFF_PTR_CALC_3]], 104
+!CHECK: %[[SZ_CALC_1_2:.*]] = sub i64 %[[BOUNDS_CALC]], 0
+!CHECK: %[[SZ_CALC_2_2:.*]] = add i64 %[[SZ_CALC_1_2]], 1
+!CHECK: %[[SZ_CALC_3_2:.*]] = mul i64 1, %[[SZ_CALC_2_2]]
+!CHECK: %[[SZ_CALC_4_2:.*]] = mul i64 %[[SZ_CALC_3_2]], 4
+!CHECK: %[[LOAD_OFF_PTR:.*]] = load ptr, ptr %[[OFF_PTR_2]], align 8
+!CHECK: %[[ARR_OFFS:.*]] = getelementptr inbounds %_QFmaptype_nested_derived_type_member_idxTvertexes, ptr %[[LOAD_OFF_PTR]], i64 0
+!CHECK: %[[LOAD_ARR_OFFS:.*]] = load ptr, ptr %[[OFF_PTR_4]], align 8
+!CHECK: %[[ARR_OFFS_1:.*]] = getelementptr inbounds i32, ptr %[[LOAD_ARR_OFFS]], i64 0
+!CHECK: %[[SZ_CALC_1:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] }, ptr %[[OFF_PTR_1]], i64 1
+!CHECK: %[[SZ_CALC_2:.*]] = ptrtoint ptr %[[SZ_CALC_1]] to i64
+!CHECK: %[[SZ_CALC_3:.*]] = ptrtoint ptr %[[OFF_PTR_1]] to i64
+!CHECK: %[[SZ_CALC_4:.*]] = sub i64 %[[SZ_CALC_2]], %[[SZ_CALC_3]]
+!CHECK: %[[SZ_CALC_5:.*]] = sdiv exact i64 %[[SZ_CALC_4]], ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64)
+!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [7 x ptr], ptr %.offload_baseptrs, i32 0, i32 0
+!CHECK: store ptr %[[BASE_PTR_1]], ptr %[[BASE_PTR_ARR]], align 8
+!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [7 x ptr], ptr %.offload_ptrs, i32 0, i32 0
+!CHECK: store ptr %[[OFF_PTR_1]], ptr %[[OFFLOAD_PTR_ARR]], align 8
+!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [7 x i64], ptr %.offload_sizes, i32 0, i32 0
+!CHECK: store i64 %[[SZ_CALC_5]], ptr %[[OFFLOAD_SIZE_ARR]], align 8
+!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [7 x ptr], ptr %.offload_baseptrs, i32 0, i32 1
+!CHECK: store ptr %[[BASE_PTR_1]], ptr %[[BASE_PTR_ARR]], align 8
+!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [7 x ptr], ptr %.offload_ptrs, i32 0, i32 1
+!CHECK: store ptr %[[OFF_PTR_1]], ptr %[[OFFLOAD_PTR_ARR]], align 8
+!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [7 x ptr], ptr %.offload_baseptrs, i32 0, i32 2
+!CHECK: store ptr %[[BASE_PTR_1]], ptr %[[BASE_PTR_ARR]], align 8
+!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [7 x ptr], ptr %.offload_ptrs, i32 0, i32 2
+!CHECK: store ptr %[[OFF_PTR_2]], ptr %[[OFFLOAD_PTR_ARR]], align 8
+!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [7 x ptr], ptr %.offload_baseptrs, i32 0, i32 3
+!CHECK: store ptr %[[OFF_PTR_2]], ptr %[[BASE_PTR_ARR]], align 8
+!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [7 x ptr], ptr %.offload_ptrs, i32 0, i32 3
+!CHECK: store ptr %[[ARR_OFFS]], ptr %[[OFFLOAD_PTR_ARR]], align 8
+!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [7 x i64], ptr %.offload_sizes, i32 0, i32 3
+!CHECK: store i64 %[[OFF_PTR_3]], ptr %[[OFFLOAD_SIZE_ARR]], align 8
+!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [7 x ptr], ptr %.offload_baseptrs, i32 0, i32 4
+!CHECK: store ptr %[[BASE_PTR_1]], ptr %[[BASE_PTR_ARR]], align 8
+!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [7 x ptr], ptr %.offload_ptrs, i32 0, i32 4
+!CHECK: store ptr %[[SZ_CALC_6]], ptr %[[OFFLOAD_PTR_ARR]], align 8
+!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [7 x ptr], ptr %.offload_baseptrs, i32 0, i32 5
+!CHECK: store ptr %[[BASE_PTR_1]], ptr %[[BASE_PTR_ARR]], align 8
+!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [7 x ptr], ptr %.offload_ptrs, i32 0, i32 5
+!CHECK: store ptr %[[OFF_PTR_4]], ptr %[[OFFLOAD_PTR_ARR]], align 8
+!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [7 x ptr], ptr %.offload_baseptrs, i32 0, i32 6
+!CHECK: store ptr %[[OFF_PTR_4]], ptr %[[BASE_PTR_ARR]], align 8
+!CHECK: %[[OFFLOAD_PTR_ARR:.*]] = getelementptr inbounds [7 x ptr], ptr %.offload_ptrs, i32 0, i32 6
+!CHECK: store ptr %[[ARR_OFFS_1]], ptr %[[OFFLOAD_PTR_ARR]], align 8
+!CHECK: %[[OFFLOAD_SIZE_ARR:.*]] = getelementptr inbounds [7 x i64], ptr %.offload_sizes, i32 0, i32 6
+!CHECK: store i64 %[[SZ_CALC_4_2]], ptr %[[OFFLOAD_SIZE_ARR]], align 8
+
!CHECK-LABEL: define {{.*}} @{{.*}}maptype_common_block_{{.*}}
!CHECK: %[[BASE_PTR_ARR:.*]] = getelementptr inbounds [1 x ptr], ptr %.offload_baseptrs, i32 0, i32 0
!CHECK: store ptr @var_common_, ptr %[[BASE_PTR_ARR]], align 8
diff --git a/flang/test/Lower/OpenMP/allocatable-array-bounds.f90 b/flang/test/Lower/OpenMP/allocatable-array-bounds.f90
index 87ca400e82e23f..e162c5a2d6d69f 100644
--- a/flang/test/Lower/OpenMP/allocatable-array-bounds.f90
+++ b/flang/test/Lower/OpenMP/allocatable-array-bounds.f90
@@ -24,7 +24,7 @@
!HOST: %[[BOUNDS_1:.*]] = omp.map.bounds lower_bound(%[[LB_1]] : index) upper_bound(%[[UB_1]] : index) extent(%[[BOX_3]]#1 : index) stride(%[[BOX_2]]#2 : index) start_idx(%[[BOX_1]]#0 : index) {stride_in_bytes = true}
!HOST: %[[VAR_PTR_PTR:.*]] = fir.box_offset %[[DECLARE_1]]#1 base_addr : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>
!HOST: %[[MAP_INFO_MEMBER:.*]] = omp.map.info var_ptr(%[[DECLARE_1]]#1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.array<?xi32>) var_ptr_ptr(%[[VAR_PTR_PTR]] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS_1]]) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>> {name = ""}
-!HOST: %[[MAP_INFO_1:.*]] = omp.map.info var_ptr(%[[DECLARE_1]]#1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.box<!fir.heap<!fir.array<?xi32>>>) map_clauses(tofrom) capture(ByRef) members(%[[MAP_INFO_MEMBER]] : [0] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>> {name = "sp_read(2:5)"}
+!HOST: %[[MAP_INFO_1:.*]] = omp.map.info var_ptr(%[[DECLARE_1]]#1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.box<!fir.heap<!fir.array<?xi32>>>) map_clauses(to) capture(ByRef) members(%[[MAP_INFO_MEMBER]] : [0] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>> {name = "sp_read(2:5)"}
!HOST: %[[LOAD_3:.*]] = fir.load %[[DECLARE_2]]#0 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
!HOST: %[[LOAD_4:.*]] = fir.load %[[DECLARE_2]]#1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
@@ -42,7 +42,7 @@
!HOST: %[[BOUNDS_2:.*]] = omp.map.bounds lower_bound(%[[LB_2]] : index) upper_bound(%[[UB_2]] : index) extent(%[[BOX_5]]#1 : index) stride(%[[BOX_4]]#2 : index) start_idx(%[[BOX_3]]#0 : index) {stride_in_bytes = true}
!HOST: %[[VAR_PTR_PTR:.*]] = fir.box_offset %[[DECLARE_2]]#1 base_addr : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>
!HOST: %[[MAP_INFO_MEMBER:.*]] = omp.map.info var_ptr(%[[DECLARE_2]]#1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.array<?xi32>) var_ptr_ptr(%[[VAR_PTR_PTR]] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS_2]]) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>> {name = ""}
-!HOST: %[[MAP_INFO_2:.*]] = omp.map.info var_ptr(%[[DECLARE_2]]#1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.box<!fir.heap<!fir.array<?xi32>>>) map_clauses(tofrom) capture(ByRef) members(%[[MAP_INFO_MEMBER]] : [0] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>> {name = "sp_write(2:5)"}
+!HOST: %[[MAP_INFO_2:.*]] = omp.map.info var_ptr(%[[DECLARE_2]]#1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.box<!fir.heap<!fir.array<?xi32>>>) map_clauses(to) capture(ByRef) members(%[[MAP_INFO_MEMBER]] : [0] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>> {name = "sp_write(2:5)"}
subroutine read_write_section()
integer, allocatable :: sp_read(:)
@@ -81,7 +81,7 @@ module assumed_allocatable_array_routines
!HOST: %[[BOUNDS:.*]] = omp.map.bounds lower_bound(%[[LB]] : index) upper_bound(%[[UB]] : index) extent(%[[BOX_3]]#1 : index) stride(%[[BOX_2]]#2 : index) start_idx(%[[BOX_1]]#0 : index) {stride_in_bytes = true}
!HOST: %[[VAR_PTR_PTR:.*]] = fir.box_offset %[[DECLARE]]#1 base_addr : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>
!HOST: %[[MAP_INFO_MEMBER:.*]] = omp.map.info var_ptr(%[[DECLARE]]#1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.array<?xi32>) var_ptr_ptr(%[[VAR_PTR_PTR]] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>> {name = ""}
-!HOST: %[[MAP_INFO:.*]] = omp.map.info var_ptr(%[[DECLARE]]#1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.box<!fir.heap<!fir.array<?xi32>>>) map_clauses(tofrom) capture(ByRef) members(%[[MAP_INFO_MEMBER]] : [0] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>> {name = "arr_read_write(2:5)"}
+!HOST: %[[MAP_INFO:.*]] = omp.map.info var_ptr(%[[DECLARE]]#1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.box<!fir.heap<!fir.array<?xi32>>>) map_clauses(to) capture(ByRef) members(%[[MAP_INFO_MEMBER]] : [0] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>> {name = "arr_read_write(2:5)"}
subroutine assumed_shape_array(arr_read_write)
integer, allocatable, intent(inout) :: arr_read_write(:)
diff --git a/flang/test/Lower/OpenMP/allocatable-map.f90 b/flang/test/Lower/OpenMP/allocatable-map.f90
index a9f576a6f09992..5c86d9f69ba39e 100644
--- a/flang/test/Lower/OpenMP/allocatable-map.f90
+++ b/flang/test/Lower/OpenMP/allocatable-map.f90
@@ -3,7 +3,7 @@
!HLFIRDIALECT: %[[POINTER:.*]]:2 = hlfir.declare %0 {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFpointer_routineEpoint"} : (!fir.ref<!fir.box<!fir.ptr<i32>>>) -> (!fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.ref<!fir.box<!fir.ptr<i32>>>)
!HLFIRDIALECT: %[[BOX_OFF:.*]] = fir.box_offset %[[POINTER]]#1 base_addr : (!fir.ref<!fir.box<!fir.ptr<i32>>>) -> !fir.llvm_ptr<!fir.ref<i32>>
!HLFIRDIALECT: %[[POINTER_MAP_MEMBER:.*]] = omp.map.info var_ptr(%[[POINTER]]#1 : !fir.ref<!fir.box<!fir.ptr<i32>>>, i32) var_ptr_ptr(%[[BOX_OFF]] : !fir.llvm_ptr<!fir.ref<i32>>) map_clauses(tofrom) capture(ByRef) -> !fir.llvm_ptr<!fir.ref<i32>> {name = ""}
-!HLFIRDIALECT: %[[POINTER_MAP:.*]] = omp.map.info var_ptr(%[[POINTER]]#1 : !fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.box<!fir.ptr<i32>>) map_clauses(tofrom) capture(ByRef) members(%[[POINTER_MAP_MEMBER]] : [0] : !fir.llvm_ptr<!fir.ref<i32>>) -> !fir.ref<!fir.box<!fir.ptr<i32>>> {name = "point"}
+!HLFIRDIALECT: %[[POINTER_MAP:.*]] = omp.map.info var_ptr(%[[POINTER]]#1 : !fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.box<!fir.ptr<i32>>) map_clauses(to) capture(ByRef) members(%[[POINTER_MAP_MEMBER]] : [0] : !fir.llvm_ptr<!fir.ref<i32>>) -> !fir.ref<!fir.box<!fir.ptr<i32>>> {name = "point"}
!HLFIRDIALECT: omp.target map_entries(%[[POINTER_MAP_MEMBER]] -> {{.*}}, %[[POINTER_MAP]] -> {{.*}} : !fir.llvm_ptr<!fir.ref<i32>>, !fir.ref<!fir.box<!fir.ptr<i32>>>) {
subroutine pointer_routine()
integer, pointer :: point
diff --git a/flang/test/Lower/OpenMP/array-bounds.f90 b/flang/test/Lower/OpenMP/array-bounds.f90
index 09498ca6cdde99..ce3d0d4584fc76 100644
--- a/flang/test/Lower/OpenMP/array-bounds.f90
+++ b/flang/test/Lower/OpenMP/array-bounds.f90
@@ -52,7 +52,7 @@ module assumed_array_routines
!HOST: %[[BOUNDS:.*]] = omp.map.bounds lower_bound(%[[C3]] : index) upper_bound(%[[C4]] : index) extent(%[[DIMS1]]#1 : index) stride(%[[DIMS0]]#2 : index) start_idx(%[[C0]] : index) {stride_in_bytes = true}
!HOST: %[[VAR_PTR_PTR:.*]] = fir.box_offset %0 base_addr : (!fir.ref<!fir.box<!fir.array<?xi32>>>) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>
!HOST: %[[MAP_INFO_MEMBER:.*]] = omp.map.info var_ptr(%[[INTERMEDIATE_ALLOCA]] : !fir.ref<!fir.box<!fir.array<?xi32>>>, !fir.array<?xi32>) var_ptr_ptr(%[[VAR_PTR_PTR]] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>> {name = ""}
-!HOST: %[[MAP:.*]] = omp.map.info var_ptr(%[[INTERMEDIATE_ALLOCA]] : !fir.ref<!fir.box<!fir.array<?xi32>>>, !fir.box<!fir.array<?xi32>>) map_clauses(tofrom) capture(ByRef) members(%[[MAP_INFO_MEMBER]] : [0] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) -> !fir.ref<!fir.array<?xi32>> {name = "arr_read_write(2:5)"}
+!HOST: %[[MAP:.*]] = omp.map.info var_ptr(%[[INTERMEDIATE_ALLOCA]] : !fir.ref<!fir.box<!fir.array<?xi32>>>, !fir.box<!fir.array<?xi32>>) map_clauses(to) capture(ByRef) members(%[[MAP_INFO_MEMBER]] : [0] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) -> !fir.ref<!fir.array<?xi32>> {name = "arr_read_write(2:5)"}
!HOST: omp.target map_entries(%[[MAP_INFO_MEMBER]] -> %{{.*}}, %[[MAP]] -> %{{.*}}, {{.*}} -> {{.*}} : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>, !fir.ref<!fir.array<?xi32>>, !fir.ref<i32>) {
subroutine assumed_shape_array(arr_read_write)
integer, intent(inout) :: arr_read_write(:)
diff --git a/flang/test/Lower/OpenMP/declare-target-link-tarop-cap.f90 b/flang/test/Lower/OpenMP/declare-target-link-tarop-cap.f90
index 3459be87fea2f0..cfdcd9eda82d1d 100644
--- a/flang/test/Lower/OpenMP/declare-target-link-tarop-cap.f90
+++ b/flang/test/Lower/OpenMP/declare-target-link-tarop-cap.f90
@@ -35,7 +35,7 @@ program test_link
allocate(test_ptr1)
test_ptr1 = 1
- !CHECK-DAG: {{%.*}} = omp.map.info var_ptr({{%.*}} : !fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.box<!fir.ptr<i32>>) map_clauses(implicit, tofrom) capture(ByRef) members({{%.*}} : !fir.llvm_ptr<!fir.ref<i32>>) -> !fir.ref<!fir.box<!fir.ptr<i32>>> {name = "test_ptr1"}
+ !CHECK-DAG: {{%.*}} = omp.map.info var_ptr({{%.*}} : !fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.box<!fir.ptr<i32>>) map_clauses(implicit, to) capture(ByRef) members({{%.*}} : !fir.llvm_ptr<!fir.ref<i32>>) -> !fir.ref<!fir.box<!fir.ptr<i32>>> {name = "test_ptr1"}
!$omp target
test_ptr1 = test_ptr1 + 1
!$omp end target
@@ -46,7 +46,7 @@ program test_link
!$omp end target
- !CHECK-DAG: {{%.*}} = omp.map.info var_ptr({{%.*}} : !fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.box<!fir.ptr<i32>>) map_clauses(implicit, tofrom) capture(ByRef) members({{%.*}} : !fir.llvm_ptr<!fir.ref<i32>>) -> !fir.ref<!fir.box<!fir.ptr<i32>>> {name = "test_ptr2"}
+ !CHECK-DAG: {{%.*}} = omp.map.info var_ptr({{%.*}} : !fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.box<!fir.ptr<i32>>) map_clauses(implicit, to) capture(ByRef) members({{%.*}} : !fir.llvm_ptr<!fir.ref<i32>>) -> !fir.ref<!fir.box<!fir.ptr<i32>>> {name = "test_ptr2"}
test_ptr2 => test_target
!$omp target
test_ptr2 = test_ptr2 + 1
diff --git a/flang/test/Lower/OpenMP/derived-type-allocatable-map.f90 b/flang/test/Lower/OpenMP/derived-type-allocatable-map.f90
new file mode 100644
index 00000000000000..ec04b66f38624a
--- /dev/null
+++ b/flang/test/Lower/OpenMP/derived-type-allocatable-map.f90
@@ -0,0 +1,161 @@
+!RUN: %flang_fc1 -emit-hlfir -fopenmp %s -o - | FileCheck %s
+
+!CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.type<[[ONE_LAYER_TY:_QFdtype_alloca_map_op_blockTone_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<\?xi32>>>,k:i32}]]> {{.*}}
+!CHECK: %[[DECLARE:.*]]:2 = hlfir.declare %[[ALLOCA]] {{{.*}}} : (!fir.ref<!fir.type<[[ONE_LAYER_TY]]>>) -> (!fir.ref<!fir.type<[[ONE_LAYER_TY]]>>, !fir.ref<!fir.type<[[ONE_LAYER_TY]]>>)
+!CHECK: %[[BOUNDS:.*]] = omp.map.bounds lower_bound({{.*}}) upper_bound({{.*}}) extent({{.*}}) stride({{.*}}) start_idx({{.*}}) {stride_in_bytes = true}
+!CHECK: %[[MEMBER_INDEX:.*]] = arith.constant 4 : index
+!CHECK: %[[MEMBER_COORD:.*]] = fir.coordinate_of %[[DECLARE]]#0, %[[MEMBER_INDEX]] : (!fir.ref<!fir.type<[[ONE_LAYER_TY]]>>, index) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+!CHECK: %[[MEMBER_BASE_ADDR:.*]] = fir.box_offset %[[MEMBER_COORD]] base_addr : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>
+!CHECK: %[[MAP_MEMBER_BASE_ADDR:.*]] = omp.map.info var_ptr(%[[MEMBER_COORD]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.array<?xi32>) var_ptr_ptr(%[[MEMBER_BASE_ADDR]] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>> {{.*}}
+!CHECK: %[[MAP_MEMBER_DESCRIPTOR:.*]] = omp.map.info var_ptr(%[[MEMBER_COORD]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.box<!fir.heap<!fir.array<?xi32>>>) map_clauses(to) capture(ByRef) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>> {{.*}}
+!CHECK: %[[MAP_PARENT:.*]] = omp.map.info var_ptr(%[[DECLARE]]#1 : !fir.ref<!fir.type<[[ONE_LAYER_TY]]>>, !fir.type<[[ONE_LAYER_TY]]>) map_clauses(tofrom) capture(ByRef) members(%[[MAP_MEMBER_DESCRIPTOR]], %[[MAP_MEMBER_BASE_ADDR]] : [4], [4, 0] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) -> !fir.ref<!fir.type<[[ONE_LAYER_TY]]>> {{{.*}} partial_map = true}
+!CHECK: omp.target map_entries(%[[MAP_MEMBER_DESCRIPTOR]] -> %[[ARG0:.*]], %[[MAP_MEMBER_BASE_ADDR]] -> %[[ARG1:.*]], %[[MAP_PARENT]] -> %[[ARG2:.*]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>, !fir.ref<!fir.type<[[ONE_LAYER_TY]]>>) {
+!CHECK: %{{.*}}:2 = hlfir.declare %[[ARG2]] {{{.*}}} : (!fir.ref<!fir.type<[[ONE_LAYER_TY]]>>) -> (!fir.ref<!fir.type<[[ONE_LAYER_TY]]>>, !fir.ref<!fir.type<[[ONE_LAYER_TY]]>>)
+subroutine dtype_alloca_map_op_block()
+ type :: one_layer
+ real(4) :: i
+ integer, allocatable :: scalar
+ integer(4) :: array_i(10)
+ real(4) :: j
+ integer, allocatable :: array_j(:)
+ integer(4) :: k
+ end type one_layer
+
+ type(one_layer) :: one_l
+
+ allocate(one_l%array_j(10))
+
+ !$omp target map(tofrom: one_l%array_j)
+ one_l%array_j(1) = 10
+ !$omp end target
+end subroutine
+
+!CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.box<!fir.heap<!fir.type<[[REC_TY:_QFalloca_dtype_op_block_addTone_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<\?xi32>>>,k:i32}]]>>> {{.*}}
+!CHECK: %[[DECLARE:.*]]:2 = hlfir.declare %[[ALLOCA]] {{{.*}}} : (!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]]>>>>)
+!CHECK: %[[BOUNDS:.*]] = omp.map.bounds lower_bound({{.*}}) upper_bound({{.*}}) extent({{.*}}) stride({{.*}}) start_idx({{.*}}) {stride_in_bytes = true}
+!CHECK: %[[LOAD_DTYPE:.*]] = fir.load %[[DECLARE]]#0 : !fir.ref<!fir.box<!fir.heap<!fir.type<[[REC_TY]]>>>>
+!CHECK: %[[MEMBER_INDEX:.*]] = arith.constant 4 : index
+!CHECK: %[[MEMBER_COORD:.*]] = fir.coordinate_of %[[LOAD_DTYPE]], %[[MEMBER_INDEX]] : (!fir.box<!fir.heap<!fir.type<[[REC_TY]]>>>, index) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+!CHECK: %[[MEMBER_BASE_ADDR:.*]] = fir.box_offset %[[MEMBER_COORD]] base_addr : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>
+!CHECK: %[[MAP_MEMBER_BASE_ADDR:.*]] = omp.map.info var_ptr(%[[MEMBER_COORD]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.array<?xi32>) var_ptr_ptr(%[[MEMBER_BASE_ADDR]] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>> {{.*}}
+!CHECK: %[[MAP_MEMBER_DESC:.*]] = omp.map.info var_ptr(%[[MEMBER_COORD]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.box<!fir.heap<!fir.array<?xi32>>>) map_clauses(to) capture(ByRef) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>> {{.*}}
+!CHECK: %[[LOAD_DTYPE:.*]] = fir.load %[[DECLARE]]#0 : !fir.ref<!fir.box<!fir.heap<!fir.type<[[REC_TY]]>>>>
+!CHECK: %[[MEMBER_COORD:.*]] = arith.constant 5 : index
+!CHECK: %[[REGULAR_MEMBER:.*]] = fir.coordinate_of %[[LOAD_DTYPE]], %[[MEMBER_COORD]] : (!fir.box<!fir.heap<!fir.type<[[REC_TY]]>>>, index) -> !fir.ref<i32>
+!CHECK: %[[MAP_REGULAR_MEMBER:.*]] = omp.map.info var_ptr(%[[REGULAR_MEMBER]] : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32> {{.*}}
+!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]]>) var_ptr_ptr(%[[DTYPE_BASE_ADDR]] : !fir.llvm_ptr<!fir.ref<!fir.type<[[REC_TY]]>>>) map_clauses(tofrom) capture(ByRef) -> !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(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_BASE_ADDR]] -> %[[ARG0:.*]], %[[MAP_MEMBER_DESC]] -> %[[ARG1:.*]], %[[MAP_MEMBER_BASE_ADDR]] -> %[[ARG2:.*]], %[[MAP_REGULAR_MEMBER]] -> %[[ARG3:.*]], %[[MAP_DTYPE_DESC]] -> %[[ARG4:.*]] : !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: %{{.*}}:2 = hlfir.declare %[[ARG4]] {{{.*}}} : (!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
+ real(4) :: i
+ integer, allocatable :: scalar
+ integer(4) :: array_i(10)
+ real(4) :: j
+ integer, allocatable :: array_j(:)
+ integer(4) :: k
+ end type one_layer
+
+ type(one_layer), allocatable :: one_l
+
+ allocate(one_l)
+ allocate(one_l%array_j(10))
+
+ !$omp target map(tofrom: one_l%array_j, one_l%k)
+ one_l%array_j(1) = 10
+ one_l%k = 20
+ !$omp end target
+end subroutine
+
+!CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.box<!fir.heap<!fir.type<[[REC_TY:_QFalloca_nest_dype_map_op_block_addTtop_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<\?xi32>>>,k:i32,nest:!fir.type<_QFalloca_nest_dype_map_op_block_addTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<\?xi32>>>,k:i32}]]>}>>> {{.*}}
+!CHECK: %[[DECLARE:.*]]:2 = hlfir.declare %[[ALLOCA]] {{.*}} : (!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]]>}>>>>)
+!CHECK: %[[BOUNDS:.*]] = omp.map.bounds lower_bound({{.*}}) upper_bound({{.*}}) extent({{.*}}) stride({{.*}}) start_idx({{.*}}) {stride_in_bytes = true}
+!CHECK: %[[LOAD:.*]] = fir.load %[[DECLARE]]#0 : !fir.ref<!fir.box<!fir.heap<!fir.type<[[REC_TY]]>}>>>>
+!CHECK: %[[NESTED_DTYPE_INDEX:.*]] = arith.constant 6 : index
+!CHECK: %[[NESTED_DTYPE_COORD:.*]] = fir.coordinate_of %[[LOAD]], %[[NESTED_DTYPE_INDEX]] : (!fir.box<!fir.heap<!fir.type<[[REC_TY]]>}>>>, index) -> !fir.ref<!fir.type<[[REC_TY2:_QFalloca_nest_dype_map_op_block_addTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<\?xi32>>>,k:i32}]]>>
+!CHECK: %[[NESTED_MEMBER_INDEX:.*]] = arith.constant 2 : index
+!CHECK: %[[NESTED_MEMBER_COORD:.*]] = fir.coordinate_of %[[NESTED_DTYPE_COORD]], %[[NESTED_MEMBER_INDEX]] : (!fir.ref<!fir.type<[[REC_TY2]]>>, index) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+!CHECK: %[[NESTED_MEMBER_BASE_ADDR:.*]] = fir.box_offset %[[NESTED_MEMBER_COORD]] base_addr : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>
+!CHECK: %[[MAP_NESTED_MEMBER_BASE_ADDR:.*]] = omp.map.info var_ptr(%[[NESTED_MEMBER_COORD]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.array<?xi32>) var_ptr_ptr(%[[NESTED_MEMBER_BASE_ADDR]] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>> {{.*}}
+!CHECK: %[[MAP_NESTED_MEMBER_COORD:.*]] = omp.map.info var_ptr(%[[NESTED_MEMBER_COORD]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.box<!fir.heap<!fir.array<?xi32>>>) map_clauses(to) capture(ByRef) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>> {{.*}}
+!CHECK: %[[LOAD:.*]] = fir.load %[[DECLARE]]#0 : !fir.ref<!fir.box<!fir.heap<!fir.type<[[REC_TY]]>}>>>>
+!CHECK: %[[NESTED_DTYPE_INDEX:.*]] = arith.constant 6 : index
+!CHECK: %[[NESTED_DTYPE_COORD:.*]] = fir.coordinate_of %[[LOAD]], %[[NESTED_DTYPE_INDEX]] : (!fir.box<!fir.heap<!fir.type<[[REC_TY]]>}>>>, index) -> !fir.ref<!fir.type<[[REC_TY2]]>>
+!CHECK: %[[NESTED_MEMBER_INDEX:.*]] = arith.constant 3 : index
+!CHECK: %[[REGULAR_NESTED_MEMBER_COORD:.*]] = fir.coordinate_of %[[NESTED_DTYPE_COORD]], %[[NESTED_MEMBER_INDEX]] : (!fir.ref<!fir.type<[[REC_TY2]]>>, index) -> !fir.ref<i32>
+!CHECK: %[[MAP_REGULAR_NESTED_MEMBER:.*]] = omp.map.info var_ptr(%[[REGULAR_NESTED_MEMBER_COORD]] : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32> {{.*}}
+!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]]>}>) var_ptr_ptr(%[[DTYPE_BASE_ADDR]] : !fir.llvm_ptr<!fir.ref<!fir.type<[[REC_TY]]>}>>>) map_clauses(tofrom) capture(ByRef) -> !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(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_BASE_ADDR]] -> %[[ARG0:.*]], %[[MAP_NESTED_MEMBER_COORD]] -> %[[ARG1:.*]], %[[MAP_NESTED_MEMBER_BASE_ADDR]] -> %[[ARG2:.*]], %[[MAP_REGULAR_NESTED_MEMBER]] -> %[[ARG3:.*]], %[[MAP_DTYPE]] -> %[[ARG4:.*]] : !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: %{{.*}}:2 = hlfir.declare %[[ARG4]] {{.*}} : (!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
+ real(4) :: i
+ integer(4) :: array_i(10)
+ integer, allocatable :: array_k(:)
+ integer(4) :: k
+ end type middle_layer
+
+ type :: top_layer
+ real(4) :: i
+ integer, allocatable :: scalar
+ integer(4) :: array_i(10)
+ real(4) :: j
+ integer, allocatable :: array_j(:)
+ integer(4) :: k
+ type(middle_layer) :: nest
+ end type top_layer
+
+ type(top_layer), allocatable :: one_l
+
+ allocate(one_l)
+ allocate(one_l%nest%array_k(10))
+
+ !$omp target map(tofrom: one_l%nest%array_k, one_l%nest%k)
+ one_l%nest%array_k(1) = 10
+ one_l%nest%k = 20
+ !$omp end target
+end subroutine
+
+!CHECK: %[[ALLOCA]] = fir.alloca !fir.type<[[REC_TY:_QFnest_dtype_alloca_map_op_block_addTtop_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<\?xi32>>>,k:i32,nest:!fir.type<_QFnest_dtype_alloca_map_op_block_addTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<\?xi32>>>,k:i32}>}]]> {{.*}}
+!CHECK: %[[DECLARE:.*]]:2 = hlfir.declare %[[ALLOCA:.*]] {{.*}} : (!fir.ref<!fir.type<[[REC_TY]]>>) -> (!fir.ref<!fir.type<[[REC_TY]]>>, !fir.ref<!fir.type<[[REC_TY]]>>)
+!CHECK: %[[BOUNDS:.*]] = omp.map.bounds lower_bound({{.*}}) upper_bound({{.*}}) extent({{.*}}) stride({{.*}}) start_idx({{.*}}) {stride_in_bytes = true}
+!CHECK: %[[NESTED_DTYPE_INDEX:.*]] = arith.constant 6 : index
+!CHECK: %[[NESTED_DTYPE_COORD:.*]] = fir.coordinate_of %[[DECLARE]]#0, %[[NESTED_DTYPE_INDEX]] : (!fir.ref<!fir.type<[[REC_TY]]>>, index) -> !fir.ref<!fir.type<[[REC_TY2:_QFnest_dtype_alloca_map_op_block_addTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<\?xi32>>>,k:i32}]]>>
+!CHECK: %[[NESTED_MEMBER_INDEX:.*]] = arith.constant 2 : index
+!CHECK: %[[NESTED_MEMBER_COORD:.*]] = fir.coordinate_of %[[NESTED_DTYPE_COORD]], %[[NESTED_MEMBER_INDEX]] : (!fir.ref<!fir.type<[[REC_TY2]]>>, index) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+!CHECK: %[[NESTED_MEMBER_BASE_ADDR:.*]] = fir.box_offset %[[NESTED_MEMBER_COORD]] base_addr : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>
+!CHECK: %[[MAP_NESTED_MEMBER_BASE_ADDR:.*]] = omp.map.info var_ptr(%[[NESTED_MEMBER_COORD]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.array<?xi32>) var_ptr_ptr(%[[NESTED_MEMBER_BASE_ADDR]] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>> {{.*}}
+!CHECK: %[[MAP_NESTED_MEMBER_DESC:.*]] = omp.map.info var_ptr(%[[NESTED_MEMBER_COORD]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.box<!fir.heap<!fir.array<?xi32>>>) map_clauses(to) capture(ByRef) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>> {{.*}}
+!CHECK: %[[MAP_PARENT:.*]] = omp.map.info var_ptr(%[[DECLARE]]#1 : !fir.ref<!fir.type<[[REC_TY]]>>, !fir.type<[[REC_TY]]>) map_clauses(tofrom) capture(ByRef) members(%[[MAP_NESTED_MEMBER_DESC]], %[[MAP_NESTED_MEMBER_BASE_ADDR]] : [6, 2], [6, 2, 0] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) -> !fir.ref<!fir.type<[[REC_TY]]>> {{.*}}
+!CHECK: omp.target map_entries(%[[MAP_NESTED_MEMBER_DESC]] -> %[[ARG0:.*]], %[[MAP_NESTED_MEMBER_BASE_ADDR]] -> %[[ARG1:.*]], %[[MAP_PARENT]] -> %[[ARG2:.*]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>, !fir.ref<!fir.type<[[REC_TY]]>>) {
+!CHECK: %{{.*}}:2 = hlfir.declare %arg2 {{.*}} : (!fir.ref<!fir.type<[[REC_TY]]>>) -> (!fir.ref<!fir.type<[[REC_TY]]>>, !fir.ref<!fir.type<[[REC_TY]]>>)
+subroutine nest_dtype_alloca_map_op_block_add()
+ type :: middle_layer
+ real(4) :: i
+ integer(4) :: array_i(10)
+ integer, allocatable :: array_k(:)
+ integer(4) :: k
+ end type middle_layer
+
+ type :: top_layer
+ real(4) :: i
+ integer, allocatable :: scalar
+ integer(4) :: array_i(10)
+ real(4) :: j
+ integer, allocatable :: array_j(:)
+ integer(4) :: k
+ type(middle_layer) :: nest
+ end type top_layer
+
+ type(top_layer) :: one_l
+
+ allocate(one_l%nest%array_k(10))
+
+ !$omp target map(tofrom: one_l%nest%array_k)
+ one_l%nest%array_k(1) = 25
+ !$omp end target
+end subroutine
diff --git a/flang/test/Lower/OpenMP/derived-type-map.f90 b/flang/test/Lower/OpenMP/derived-type-map.f90
index d1eed74a4270ce..3a2b7efb46094b 100644
--- a/flang/test/Lower/OpenMP/derived-type-map.f90
+++ b/flang/test/Lower/OpenMP/derived-type-map.f90
@@ -105,7 +105,7 @@ end subroutine mapType_derived_explicit_member_with_bounds
!CHECK: %[[NEST_MEMBER:.*]] = hlfir.designate %[[NEST]]{"array"} shape %{{.*}} : (!fir.ref<!fir.type<_QFmaptype_derived_nested_explicit_single_memberTnested{int:i32,real:f32,array:!fir.array<10xi32>}>>, !fir.shape<1>) -> !fir.ref<!fir.array<10xi32>>
!CHECK: %[[BOUNDS:.*]] = omp.map.bounds lower_bound(%{{.*}} : index) upper_bound(%{{.*}} : index) extent(%{{.*}} : index) stride(%{{.*}} : index) start_idx(%{{.*}} : index)
!CHECK: %[[MEMBER_MAP:.*]] = omp.map.info var_ptr(%[[NEST_MEMBER]] : !fir.ref<!fir.array<10xi32>>, !fir.array<10xi32>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.ref<!fir.array<10xi32>> {name = "scalar_arr%nest%array"}
-!CHECK: %[[PARENT_MAP:.*]] = omp.map.info var_ptr(%[[DECLARE]]#1 : {{.*}}) map_clauses(tofrom) capture(ByRef) members(%35 : [2,2] : !fir.ref<!fir.array<10xi32>>) -> {{.*}} {name = "scalar_arr", partial_map = true}
+!CHECK: %[[PARENT_MAP:.*]] = omp.map.info var_ptr(%[[DECLARE]]#1 : {{.*}}) map_clauses(tofrom) capture(ByRef) members(%35 : [2, 2] : !fir.ref<!fir.array<10xi32>>) -> {{.*}} {name = "scalar_arr", partial_map = true}
!CHECK: omp.target map_entries(%[[MEMBER_MAP]] -> %[[ARG0:.*]], %[[PARENT_MAP]] -> %[[ARG1:.*]] : {{.*}}, {{.*}}) {
subroutine mapType_derived_nested_explicit_single_member
type :: nested
@@ -136,7 +136,7 @@ end subroutine mapType_derived_nested_explicit_single_member
!CHECK: %[[NEST:.*]] = hlfir.designate %[[DECLARE]]#0{"nest"} : ({{.*}}) -> {{.*}}
!CHECK: %[[NEST_MEMBER2:.*]] = hlfir.designate %[[NEST]]{"real"} : ({{.*}}) -> !fir.ref<f32>
!CHECK: %[[MEMBER_MAP_2:.*]] = omp.map.info var_ptr(%[[NEST_MEMBER2]] : !fir.ref<f32>, f32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<f32> {name = "scalar_arr%nest%real"}
-!CHECK: %[[PARENT_MAP:.*]] = omp.map.info var_ptr(%[[DECLARE]]#1 : {{.*}}, {{.*}}) map_clauses(tofrom) capture(ByRef) members(%[[MEMBER_MAP_1]], %[[MEMBER_MAP_2]] : [2,0], [2,1] : !fir.ref<i32>, !fir.ref<f32>) -> {{.*}} {name = "scalar_arr", partial_map = true}
+!CHECK: %[[PARENT_MAP:.*]] = omp.map.info var_ptr(%[[DECLARE]]#1 : {{.*}}, {{.*}}) map_clauses(tofrom) capture(ByRef) members(%[[MEMBER_MAP_1]], %[[MEMBER_MAP_2]] : [2, 0], [2, 1] : !fir.ref<i32>, !fir.ref<f32>) -> {{.*}} {name = "scalar_arr", partial_map = true}
!CHECK: omp.target map_entries(%[[MEMBER_MAP_1]] -> %[[ARG0:.*]], %[[MEMBER_MAP_2]] -> %[[ARG1:.*]], %[[PARENT_MAP]] -> %[[ARG2:.*]] : !fir.ref<i32>, !fir.ref<f32>, {{.*}}) {
subroutine mapType_derived_nested_explicit_multiple_members
type :: nested
@@ -169,7 +169,7 @@ end subroutine mapType_derived_nested_explicit_multiple_members
!CHECK: %[[C4:.*]] = arith.constant 4 : index
!CHECK: %[[BOUNDS:.*]] = omp.map.bounds lower_bound(%[[C1_2]] : index) upper_bound(%[[C4]] : index) extent(%[[C10]] : index) stride(%[[C1]] : index) start_idx(%[[C1]] : index)
!CHECK: %[[MEMBER_MAP:.*]] = omp.map.info var_ptr(%[[NEST_MEMBER]] : !fir.ref<!fir.array<10xi32>>, !fir.array<10xi32>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.ref<!fir.array<10xi32>> {name = "scalar_arr%nest%array(2:5)"}
-!CHECK: %[[PARENT_MAP:.*]] = omp.map.info var_ptr(%[[DECLARE]]#1 : {{.*}}, {{.*}}) map_clauses(tofrom) capture(ByRef) members(%[[MEMBER_MAP]] : [2,2] : !fir.ref<!fir.array<10xi32>>) -> {{.*}} {name = "scalar_arr", partial_map = true}
+!CHECK: %[[PARENT_MAP:.*]] = omp.map.info var_ptr(%[[DECLARE]]#1 : {{.*}}, {{.*}}) map_clauses(tofrom) capture(ByRef) members(%[[MEMBER_MAP]] : [2, 2] : !fir.ref<!fir.array<10xi32>>) -> {{.*}} {name = "scalar_arr", partial_map = true}
!CHECK: omp.target map_entries(%[[MEMBER_MAP]] -> %[[ARG0:.*]], %[[PARENT_MAP]] -> %[[ARG1:.*]] : !fir.ref<!fir.array<10xi32>>, {{.*}}) {
subroutine mapType_derived_nested_explicit_member_with_bounds
type :: nested
@@ -202,8 +202,8 @@ end subroutine mapType_derived_nested_explicit_member_with_bounds
!CHECK: %[[PARENT_2:.*]] = hlfir.designate %[[DECLARE_2]]#0{"nest"} : {{.*}} -> {{.*}}
!CHECK: %[[MEMBER_2:.*]] = hlfir.designate %[[PARENT_2]]{"int"} : {{.*}} -> !fir.ref<i32>
!CHECK: %[[MAP_MEMBER_2:.*]] = omp.map.info var_ptr(%[[MEMBER_2]] : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32> {name = "scalar_arr2%nest%int"}
-!CHECK: %[[MAP_PARENT_1:.*]] = omp.map.info var_ptr(%[[DECLARE_1]]#1 : {{.*}}) map_clauses(tofrom) capture(ByRef) members(%[[MAP_MEMBER_1]] : [2,0] : !fir.ref<i32>) -> {{.*}} {name = "scalar_arr1", partial_map = true}
-!CHECK: %[[MAP_PARENT_2:.*]] = omp.map.info var_ptr(%[[DECLARE_2]]#1 : {{.*}}) map_clauses(tofrom) capture(ByRef) members(%[[MAP_MEMBER_2]] : [2,0] : !fir.ref<i32>) -> {{.*}} {name = "scalar_arr2", partial_map = true}
+!CHECK: %[[MAP_PARENT_1:.*]] = omp.map.info var_ptr(%[[DECLARE_1]]#1 : {{.*}}) map_clauses(tofrom) capture(ByRef) members(%[[MAP_MEMBER_1]] : [2, 0] : !fir.ref<i32>) -> {{.*}} {name = "scalar_arr1", partial_map = true}
+!CHECK: %[[MAP_PARENT_2:.*]] = omp.map.info var_ptr(%[[DECLARE_2]]#1 : {{.*}}) map_clauses(tofrom) capture(ByRef) members(%[[MAP_MEMBER_2]] : [2, 0] : !fir.ref<i32>) -> {{.*}} {name = "scalar_arr2", partial_map = true}
!CHECK: omp.target map_entries(%[[MAP_MEMBER_1]] -> %[[ARG0:.*]], %[[MAP_PARENT_1]] -> %[[ARG1:.*]], %[[MAP_MEMBER_2]] -> %[[ARG2:.*]], %[[MAP_PARENT_2:.*]] -> %[[ARG3:.*]] : !fir.ref<i32>, {{.*}}, !fir.ref<i32>, {{.*}}) {
subroutine mapType_multilpe_derived_nested_explicit_member
type :: nested
diff --git a/flang/test/Lower/OpenMP/target.f90 b/flang/test/Lower/OpenMP/target.f90
index 63a43e750979d5..56d040afab42b7 100644
--- a/flang/test/Lower/OpenMP/target.f90
+++ b/flang/test/Lower/OpenMP/target.f90
@@ -525,9 +525,9 @@ subroutine omp_target_device_addr
!CHECK: %[[VAL_0:.*]] = fir.alloca !fir.box<!fir.ptr<i32>> {bindc_name = "a", uniq_name = "_QFomp_target_device_addrEa"}
!CHECK: %[[VAL_0_DECL:.*]]:2 = hlfir.declare %0 {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFomp_target_device_addrEa"} : (!fir.ref<!fir.box<!fir.ptr<i32>>>) -> (!fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.ref<!fir.box<!fir.ptr<i32>>>)
!CHECK: %[[MAP_MEMBERS:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref<!fir.box<!fir.ptr<i32>>>, i32) var_ptr_ptr({{.*}} : !fir.llvm_ptr<!fir.ref<i32>>) map_clauses(tofrom) capture(ByRef) -> !fir.llvm_ptr<!fir.ref<i32>> {name = ""}
- !CHECK: %[[MAP:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.box<!fir.ptr<i32>>) map_clauses(tofrom) capture(ByRef) members(%[[MAP_MEMBERS]] : [0] : !fir.llvm_ptr<!fir.ref<i32>>) -> !fir.ref<!fir.box<!fir.ptr<i32>>> {name = "a"}
+ !CHECK: %[[MAP:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.box<!fir.ptr<i32>>) map_clauses(to) capture(ByRef) members(%[[MAP_MEMBERS]] : [0] : !fir.llvm_ptr<!fir.ref<i32>>) -> !fir.ref<!fir.box<!fir.ptr<i32>>> {name = "a"}
!CHECK: %[[DEV_ADDR_MEMBERS:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref<!fir.box<!fir.ptr<i32>>>, i32) var_ptr_ptr({{.*}} : !fir.llvm_ptr<!fir.ref<i32>>) map_clauses(tofrom) capture(ByRef) -> !fir.llvm_ptr<!fir.ref<i32>> {name = ""}
- !CHECK: %[[DEV_ADDR:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.box<!fir.ptr<i32>>) map_clauses(tofrom) capture(ByRef) members(%[[DEV_ADDR_MEMBERS]] : [0] : !fir.llvm_ptr<!fir.ref<i32>>) -> !fir.ref<!fir.box<!fir.ptr<i32>>> {name = "a"}
+ !CHECK: %[[DEV_ADDR:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.box<!fir.ptr<i32>>) map_clauses(to) capture(ByRef) members(%[[DEV_ADDR_MEMBERS]] : [0] : !fir.llvm_ptr<!fir.ref<i32>>) -> !fir.ref<!fir.box<!fir.ptr<i32>>> {name = "a"}
!CHECK: omp.target_data map_entries(%[[MAP_MEMBERS]], %[[MAP]] : {{.*}}) use_device_addr(%[[DEV_ADDR_MEMBERS]] -> %[[ARG_0:.*]], %[[DEV_ADDR]] -> %[[ARG_1:.*]] : !fir.llvm_ptr<!fir.ref<i32>>, !fir.ref<!fir.box<!fir.ptr<i32>>>) {
!$omp target data map(tofrom: a) use_device_addr(a)
!CHECK: %[[VAL_1_DECL:.*]]:2 = hlfir.declare %[[ARG_1]] {fortran_attrs = #fir.var_attrs<pointer>, uniq_name = "_QFomp_target_device_addrEa"} : (!fir.ref<!fir.box<!fir.ptr<i32>>>) -> (!fir.ref<!fir.box<!fir.ptr<i32>>>, !fir.ref<!fir.box<!fir.ptr<i32>>>)
diff --git a/flang/test/Transforms/omp-map-info-finalization.fir b/flang/test/Transforms/omp-map-info-finalization.fir
index fa7b65d41929b7..dac02d19ecf2aa 100644
--- a/flang/test/Transforms/omp-map-info-finalization.fir
+++ b/flang/test/Transforms/omp-map-info-finalization.fir
@@ -1,31 +1,29 @@
// RUN: fir-opt --split-input-file --omp-map-info-finalization %s | FileCheck %s
-module attributes {omp.is_target_device = false} {
- func.func @test_descriptor_expansion_pass(%arg0: !fir.box<!fir.array<?xi32>>) {
- %0 = fir.alloca !fir.box<!fir.heap<i32>>
- %1 = fir.zero_bits !fir.heap<i32>
- %2:2 = hlfir.declare %arg0 {fortran_attrs = #fir.var_attrs<intent_out>, uniq_name = "test"} : (!fir.box<!fir.array<?xi32>>) -> (!fir.box<!fir.array<?xi32>>, !fir.box<!fir.array<?xi32>>)
- %3 = fir.embox %1 : (!fir.heap<i32>) -> !fir.box<!fir.heap<i32>>
- fir.store %3 to %0 : !fir.ref<!fir.box<!fir.heap<i32>>>
- %4:2 = hlfir.declare %0 {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "test2"} : (!fir.ref<!fir.box<!fir.heap<i32>>>) -> (!fir.ref<!fir.box<!fir.heap<i32>>>, !fir.ref<!fir.box<!fir.heap<i32>>>)
- %5 = fir.allocmem i32 {fir.must_be_heap = true}
- %6 = fir.embox %5 : (!fir.heap<i32>) -> !fir.box<!fir.heap<i32>>
- fir.store %6 to %4#1 : !fir.ref<!fir.box<!fir.heap<i32>>>
- %c0 = arith.constant 1 : index
- %c1 = arith.constant 0 : index
- %c2 = arith.constant 10 : index
- %dims:3 = fir.box_dims %2#1, %c1 : (!fir.box<!fir.array<?xi32>>, index) -> (index, index, index)
- %bounds = omp.map.bounds lower_bound(%c1 : index) upper_bound(%c2 : index) extent(%dims#1 : index) stride(%dims#2 : index) start_idx(%c0 : index) {stride_in_bytes = true}
- %7 = fir.box_addr %2#1 : (!fir.box<!fir.array<?xi32>>) -> !fir.ref<!fir.array<?xi32>>
- %8 = omp.map.info var_ptr(%4#1 : !fir.ref<!fir.box<!fir.heap<i32>>>, !fir.box<!fir.heap<i32>>) map_clauses(tofrom) capture(ByRef) -> !fir.ref<!fir.box<!fir.heap<i32>>>
- %9 = omp.map.info var_ptr(%7 : !fir.ref<!fir.array<?xi32>>, !fir.array<?xi32>) map_clauses(from) capture(ByRef) bounds(%bounds) -> !fir.ref<!fir.array<?xi32>>
- omp.target map_entries(%8 -> %arg1, %9 -> %arg2 : !fir.ref<!fir.box<!fir.heap<i32>>>, !fir.ref<!fir.array<?xi32>>) {
- omp.terminator
- }
- return
+func.func @test_descriptor_expansion_pass(%arg0: !fir.box<!fir.array<?xi32>>) {
+ %0 = fir.alloca !fir.box<!fir.heap<i32>>
+ %1 = fir.zero_bits !fir.heap<i32>
+ %2:2 = hlfir.declare %arg0 {fortran_attrs = #fir.var_attrs<intent_out>, uniq_name = "test"} : (!fir.box<!fir.array<?xi32>>) -> (!fir.box<!fir.array<?xi32>>, !fir.box<!fir.array<?xi32>>)
+ %3 = fir.embox %1 : (!fir.heap<i32>) -> !fir.box<!fir.heap<i32>>
+ fir.store %3 to %0 : !fir.ref<!fir.box<!fir.heap<i32>>>
+ %4:2 = hlfir.declare %0 {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "test2"} : (!fir.ref<!fir.box<!fir.heap<i32>>>) -> (!fir.ref<!fir.box<!fir.heap<i32>>>, !fir.ref<!fir.box<!fir.heap<i32>>>)
+ %5 = fir.allocmem i32 {fir.must_be_heap = true}
+ %6 = fir.embox %5 : (!fir.heap<i32>) -> !fir.box<!fir.heap<i32>>
+ fir.store %6 to %4#1 : !fir.ref<!fir.box<!fir.heap<i32>>>
+ %c0 = arith.constant 1 : index
+ %c1 = arith.constant 0 : index
+ %c2 = arith.constant 10 : index
+ %dims:3 = fir.box_dims %2#1, %c1 : (!fir.box<!fir.array<?xi32>>, index) -> (index, index, index)
+ %bounds = omp.map.bounds lower_bound(%c1 : index) upper_bound(%c2 : index) extent(%dims#1 : index) stride(%dims#2 : index) start_idx(%c0 : index) {stride_in_bytes = true}
+ %7 = fir.box_addr %2#1 : (!fir.box<!fir.array<?xi32>>) -> !fir.ref<!fir.array<?xi32>>
+ %8 = omp.map.info var_ptr(%4#1 : !fir.ref<!fir.box<!fir.heap<i32>>>, !fir.box<!fir.heap<i32>>) map_clauses(tofrom) capture(ByRef) -> !fir.ref<!fir.box<!fir.heap<i32>>>
+ %9 = omp.map.info var_ptr(%7 : !fir.ref<!fir.array<?xi32>>, !fir.array<?xi32>) map_clauses(from) capture(ByRef) bounds(%bounds) -> !fir.ref<!fir.array<?xi32>>
+ omp.target map_entries(%8 -> %arg1, %9 -> %arg2 : !fir.ref<!fir.box<!fir.heap<i32>>>, !fir.ref<!fir.array<?xi32>>) {
+ omp.terminator
}
+ return
}
-
+
// CHECK: func.func @test_descriptor_expansion_pass(%[[ARG0:.*]]: !fir.box<!fir.array<?xi32>>) {
// CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.box<!fir.array<?xi32>>
// CHECK: %[[ALLOCA2:.*]] = fir.alloca !fir.box<!fir.heap<i32>>
@@ -34,27 +32,25 @@ module attributes {omp.is_target_device = false} {
// CHECK: %[[BOUNDS:.*]] = omp.map.bounds lower_bound(%{{.*}} : index) upper_bound(%{{.*}} : index) extent(%{{.*}} : index) stride(%{{.*}} : index) start_idx(%{{.*}} : index) {stride_in_bytes = true}
// CHECK: %[[BASE_ADDR_OFF:.*]] = fir.box_offset %[[DECLARE2]]#1 base_addr : (!fir.ref<!fir.box<!fir.heap<i32>>>) -> !fir.llvm_ptr<!fir.ref<i32>>
// CHECK: %[[DESC_MEMBER_MAP:.*]] = omp.map.info var_ptr(%[[DECLARE2]]#1 : !fir.ref<!fir.box<!fir.heap<i32>>>, i32) var_ptr_ptr(%[[BASE_ADDR_OFF]] : !fir.llvm_ptr<!fir.ref<i32>>) map_clauses(tofrom) capture(ByRef) -> !fir.llvm_ptr<!fir.ref<i32>> {name = ""}
-// CHECK: %[[DESC_PARENT_MAP:.*]] = omp.map.info var_ptr(%[[DECLARE2]]#1 : !fir.ref<!fir.box<!fir.heap<i32>>>, !fir.box<!fir.heap<i32>>) map_clauses(tofrom) capture(ByRef) members(%[[DESC_MEMBER_MAP]] : [0] : !fir.llvm_ptr<!fir.ref<i32>>) -> !fir.ref<!fir.box<!fir.heap<i32>>>
+// CHECK: %[[DESC_PARENT_MAP:.*]] = omp.map.info var_ptr(%[[DECLARE2]]#1 : !fir.ref<!fir.box<!fir.heap<i32>>>, !fir.box<!fir.heap<i32>>) map_clauses(to) capture(ByRef) members(%[[DESC_MEMBER_MAP]] : [0] : !fir.llvm_ptr<!fir.ref<i32>>) -> !fir.ref<!fir.box<!fir.heap<i32>>>
// CHECK: fir.store %[[DECLARE1]]#1 to %[[ALLOCA]] : !fir.ref<!fir.box<!fir.array<?xi32>>>
// CHECK: %[[BASE_ADDR_OFF_2:.*]] = fir.box_offset %[[ALLOCA]] base_addr : (!fir.ref<!fir.box<!fir.array<?xi32>>>) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>
// CHECK: %[[DESC_MEMBER_MAP_2:.*]] = omp.map.info var_ptr(%[[ALLOCA]] : !fir.ref<!fir.box<!fir.array<?xi32>>>, !fir.array<?xi32>) var_ptr_ptr(%[[BASE_ADDR_OFF_2]] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) map_clauses(from) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>> {name = ""}
-// CHECK: %[[DESC_PARENT_MAP_2:.*]] = omp.map.info var_ptr(%[[ALLOCA]] : !fir.ref<!fir.box<!fir.array<?xi32>>>, !fir.box<!fir.array<?xi32>>) map_clauses(from) capture(ByRef) members(%[[DESC_MEMBER_MAP_2]] : [0] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) -> !fir.ref<!fir.array<?xi32>>
+// CHECK: %[[DESC_PARENT_MAP_2:.*]] = omp.map.info var_ptr(%[[ALLOCA]] : !fir.ref<!fir.box<!fir.array<?xi32>>>, !fir.box<!fir.array<?xi32>>) map_clauses(to) capture(ByRef) members(%[[DESC_MEMBER_MAP_2]] : [0] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) -> !fir.ref<!fir.array<?xi32>
// CHECK: omp.target map_entries(%[[DESC_MEMBER_MAP]] -> %[[ARG1:.*]], %[[DESC_PARENT_MAP]] -> %[[ARG2:.*]], %[[DESC_MEMBER_MAP_2]] -> %[[ARG3:.*]], %[[DESC_PARENT_MAP_2]] -> %[[ARG4:.*]] : {{.*}}) {
// -----
-module attributes {omp.is_target_device = false} {
- func.func @test_derived_type_map_operand_and_block_addition(%arg0: !fir.ref<!fir.type<_QFTdtype{ix:i32,rx:f32,zx:complex<f32>,nested:!fir.box<!fir.heap<!fir.type<_QFTdtype>>>,ry:f32}>>) {
- %0 = hlfir.designate %arg0{"rx"} : (!fir.ref<!fir.type<_QFTdtype{ix:i32,rx:f32,zx:complex<f32>,nested:!fir.box<!fir.heap<!fir.type<_QFTdtype>>>,ry:f32}>>) -> !fir.ref<f32>
- %1 = omp.map.info var_ptr(%0 : !fir.ref<f32>, f32) map_clauses(from) capture(ByRef) -> !fir.ref<f32> {name = "scalar_struct%rx"}
- %2 = hlfir.designate %arg0{"ry"} : (!fir.ref<!fir.type<_QFTdtype{ix:i32,rx:f32,zx:complex<f32>,nested:!fir.box<!fir.heap<!fir.type<_QFTdtype>>>,ry:f32}>>) -> !fir.ref<f32>
- %3 = omp.map.info var_ptr(%2 : !fir.ref<f32>, f32) map_clauses(from) capture(ByRef) -> !fir.ref<f32> {name = "scalar_struct%ry"}
- %4 = omp.map.info var_ptr(%arg0 : !fir.ref<!fir.type<_QFTdtype{ix:i32,rx:f32,zx:complex<f32>,nested:!fir.box<!fir.heap<!fir.type<_QFTdtype>>>,ry:f32}>>, !fir.type<_QFTdtype{ix:i32,rx:f32,zx:complex<f32>,nested:!fir.box<!fir.heap<!fir.type<_QFTdtype>>>,ry:f32}>) map_clauses(from) capture(ByRef) members(%1, %3 : [1], [4] : !fir.ref<f32>, !fir.ref<f32>) -> !fir.ref<!fir.type<_QFTdtype{ix:i32,rx:f32,zx:complex<f32>,nested:!fir.box<!fir.heap<!fir.type<_QFTdtype>>>,ry:f32}>> {name = "scalar_struct", partial_map = true}
- omp.target map_entries(%4 -> %arg1 : !fir.ref<!fir.type<_QFTdtype{ix:i32,rx:f32,zx:complex<f32>,nested:!fir.box<!fir.heap<!fir.type<_QFTdtype>>>,ry:f32}>>) {
- omp.terminator
- }
- return
+func.func @test_derived_type_map_operand_and_block_addition(%arg0: !fir.ref<!fir.type<_QFTdtype{ix:i32,rx:f32,zx:complex<f32>,nested:!fir.box<!fir.heap<!fir.type<_QFTdtype>>>,ry:f32}>>) {
+ %0 = hlfir.designate %arg0{"rx"} : (!fir.ref<!fir.type<_QFTdtype{ix:i32,rx:f32,zx:complex<f32>,nested:!fir.box<!fir.heap<!fir.type<_QFTdtype>>>,ry:f32}>>) -> !fir.ref<f32>
+ %1 = omp.map.info var_ptr(%0 : !fir.ref<f32>, f32) map_clauses(from) capture(ByRef) -> !fir.ref<f32> {name = "scalar_struct%rx"}
+ %2 = hlfir.designate %arg0{"ry"} : (!fir.ref<!fir.type<_QFTdtype{ix:i32,rx:f32,zx:complex<f32>,nested:!fir.box<!fir.heap<!fir.type<_QFTdtype>>>,ry:f32}>>) -> !fir.ref<f32>
+ %3 = omp.map.info var_ptr(%2 : !fir.ref<f32>, f32) map_clauses(from) capture(ByRef) -> !fir.ref<f32> {name = "scalar_struct%ry"}
+ %4 = omp.map.info var_ptr(%arg0 : !fir.ref<!fir.type<_QFTdtype{ix:i32,rx:f32,zx:complex<f32>,nested:!fir.box<!fir.heap<!fir.type<_QFTdtype>>>,ry:f32}>>, !fir.type<_QFTdtype{ix:i32,rx:f32,zx:complex<f32>,nested:!fir.box<!fir.heap<!fir.type<_QFTdtype>>>,ry:f32}>) map_clauses(from) capture(ByRef) members(%1, %3 : [1], [4] : !fir.ref<f32>, !fir.ref<f32>) -> !fir.ref<!fir.type<_QFTdtype{ix:i32,rx:f32,zx:complex<f32>,nested:!fir.box<!fir.heap<!fir.type<_QFTdtype>>>,ry:f32}>> {name = "scalar_struct", partial_map = true}
+ omp.target map_entries(%4 -> %arg1 : !fir.ref<!fir.type<_QFTdtype{ix:i32,rx:f32,zx:complex<f32>,nested:!fir.box<!fir.heap<!fir.type<_QFTdtype>>>,ry:f32}>>) {
+ omp.terminator
}
+ return
}
// CHECK: func.func @test_derived_type_map_operand_and_block_addition(%{{.*}}: !fir.ref<!fir.type<_QFTdtype{ix:i32,rx:f32,zx:complex<f32>,nested:!fir.box<!fir.heap<!fir.type<_QFTdtype>>>,ry:f32}>>) {
@@ -65,29 +61,238 @@ module attributes {omp.is_target_device = false} {
// -----
-module attributes {omp.is_target_device = false} {
func.func @test_nested_derived_type_map_operand_and_block_addition(%arg0: !fir.ref<!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTscalar_and_array{r:f32,n:!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTnested{i:i32,r:f32}>}>>) {
- %0 = fir.declare %arg0 {uniq_name = "_QFmaptype_derived_nested_explicit_multiple_membersEsa"} : (!fir.ref<!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTscalar_and_array{r:f32,n:!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTnested{i:i32,r:f32}>}>>) -> !fir.ref<!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTscalar_and_array{r:f32,n:!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTnested{i:i32,r:f32}>}>>
- %1 = fir.field_index n, !fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTscalar_and_array{r:f32,n:!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTnested{i:i32,r:f32}>}>
- %2 = fir.coordinate_of %0, %1 : (!fir.ref<!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTscalar_and_array{r:f32,n:!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTnested{i:i32,r:f32}>}>>, !fir.field) -> !fir.ref<!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTnested{i:i32,r:f32}>>
- %3 = fir.field_index i, !fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTnested{i:i32,r:f32}>
- %4 = fir.coordinate_of %2, %3 : (!fir.ref<!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTnested{i:i32,r:f32}>>, !fir.field) -> !fir.ref<i32>
- %5 = omp.map.info var_ptr(%4 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32> {name = "sa%n%i"}
- %6 = fir.field_index n, !fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTscalar_and_array{r:f32,n:!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTnested{i:i32,r:f32}>}>
- %7 = fir.coordinate_of %0, %6 : (!fir.ref<!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTscalar_and_array{r:f32,n:!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTnested{i:i32,r:f32}>}>>, !fir.field) -> !fir.ref<!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTnested{i:i32,r:f32}>>
- %8 = fir.field_index r, !fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTnested{i:i32,r:f32}>
- %9 = fir.coordinate_of %7, %8 : (!fir.ref<!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTnested{i:i32,r:f32}>>, !fir.field) -> !fir.ref<f32>
- %10 = omp.map.info var_ptr(%9 : !fir.ref<f32>, f32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<f32> {name = "sa%n%r"}
- %11 = omp.map.info var_ptr(%0 : !fir.ref<!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTscalar_and_array{r:f32,n:!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTnested{i:i32,r:f32}>}>>, !fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTscalar_and_array{r:f32,n:!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTnested{i:i32,r:f32}>}>) map_clauses(tofrom) capture(ByRef) members(%5, %10 : [1,0], [1,1] : !fir.ref<i32>, !fir.ref<f32>) -> !fir.ref<!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTscalar_and_array{r:f32,n:!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTnested{i:i32,r:f32}>}>> {name = "sa", partial_map = true}
- omp.target map_entries(%11 -> %arg1 : !fir.ref<!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTscalar_and_array{r:f32,n:!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTnested{i:i32,r:f32}>}>>) {
- omp.terminator
- }
- return
+ %0 = fir.declare %arg0 {uniq_name = "_QFmaptype_derived_nested_explicit_multiple_membersEsa"} : (!fir.ref<!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTscalar_and_array{r:f32,n:!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTnested{i:i32,r:f32}>}>>) -> !fir.ref<!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTscalar_and_array{r:f32,n:!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTnested{i:i32,r:f32}>}>>
+ %1 = fir.field_index n, !fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTscalar_and_array{r:f32,n:!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTnested{i:i32,r:f32}>}>
+ %2 = fir.coordinate_of %0, %1 : (!fir.ref<!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTscalar_and_array{r:f32,n:!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTnested{i:i32,r:f32}>}>>, !fir.field) -> !fir.ref<!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTnested{i:i32,r:f32}>>
+ %3 = fir.field_index i, !fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTnested{i:i32,r:f32}>
+ %4 = fir.coordinate_of %2, %3 : (!fir.ref<!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTnested{i:i32,r:f32}>>, !fir.field) -> !fir.ref<i32>
+ %5 = omp.map.info var_ptr(%4 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32> {name = "sa%n%i"}
+ %6 = fir.field_index n, !fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTscalar_and_array{r:f32,n:!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTnested{i:i32,r:f32}>}>
+ %7 = fir.coordinate_of %0, %6 : (!fir.ref<!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTscalar_and_array{r:f32,n:!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTnested{i:i32,r:f32}>}>>, !fir.field) -> !fir.ref<!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTnested{i:i32,r:f32}>>
+ %8 = fir.field_index r, !fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTnested{i:i32,r:f32}>
+ %9 = fir.coordinate_of %7, %8 : (!fir.ref<!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTnested{i:i32,r:f32}>>, !fir.field) -> !fir.ref<f32>
+ %10 = omp.map.info var_ptr(%9 : !fir.ref<f32>, f32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<f32> {name = "sa%n%r"}
+ %11 = omp.map.info var_ptr(%0 : !fir.ref<!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTscalar_and_array{r:f32,n:!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTnested{i:i32,r:f32}>}>>, !fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTscalar_and_array{r:f32,n:!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTnested{i:i32,r:f32}>}>) map_clauses(tofrom) capture(ByRef) members(%5, %10 : [1,0], [1,1] : !fir.ref<i32>, !fir.ref<f32>) -> !fir.ref<!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTscalar_and_array{r:f32,n:!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTnested{i:i32,r:f32}>}>> {name = "sa", partial_map = true}
+ omp.target map_entries(%11 -> %arg1 : !fir.ref<!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTscalar_and_array{r:f32,n:!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTnested{i:i32,r:f32}>}>>) {
+ omp.terminator
}
+ return
}
// CHECK: func.func @test_nested_derived_type_map_operand_and_block_addition(%{{.*}}: !fir.ref<!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTscalar_and_array{r:f32,n:!fir.type<_QFmaptype_derived_nested_explicit_multiple_membersTnested{i:i32,r:f32}>}>>) {
// CHECK: %[[MAP_MEMBER_1:.*]] = omp.map.info var_ptr(%{{.*}} : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32> {name = "sa%n%i"}
// CHECK: %[[MAP_MEMBER_2:.*]] = omp.map.info var_ptr(%{{.*}} : !fir.ref<f32>, f32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<f32> {name = "sa%n%r"}
-// CHECK: %[[MAP_PARENT:.*]] = omp.map.info var_ptr(%{{.*}} : {{.*}}, {{.*}}) map_clauses(tofrom) capture(ByRef) members(%[[MAP_MEMBER_1]], %[[MAP_MEMBER_2]] : [1,0], [1,1] : !fir.ref<i32>, !fir.ref<f32>) -> {{.*}} {name = "sa", partial_map = true}
+// CHECK: %[[MAP_PARENT:.*]] = omp.map.info var_ptr(%{{.*}} : {{.*}}, {{.*}}) map_clauses(tofrom) capture(ByRef) members(%[[MAP_MEMBER_1]], %[[MAP_MEMBER_2]] : [1, 0], [1, 1] : !fir.ref<i32>, !fir.ref<f32>) -> {{.*}} {name = "sa", partial_map = true}
// CHECK: omp.target map_entries(%[[MAP_MEMBER_1]] -> %[[ARG1:.*]], %[[MAP_MEMBER_2]] -> %[[ARG2:.*]], %[[MAP_PARENT]] -> %[[ARG3:.*]] : !fir.ref<i32>, !fir.ref<f32>, {{.*}}) {
+
+// -----
+
+func.func @dtype_alloca_op_block_add(%arg0: !fir.ref<!fir.type<_QFtest_derived_type_allocatable_map_operand_and_block_additionTone_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>) {
+ %0:2 = hlfir.declare %arg0 {uniq_name = "_QFtest_derived_type_allocatable_map_operand_and_block_additionEone_l"} : (!fir.ref<!fir.type<_QFtest_derived_type_allocatable_map_operand_and_block_additionTone_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>) -> (!fir.ref<!fir.type<_QFtest_derived_type_allocatable_map_operand_and_block_additionTone_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>, !fir.ref<!fir.type<_QFtest_derived_type_allocatable_map_operand_and_block_additionTone_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>)
+ %1 = hlfir.designate %0#0{"array_j"} {fortran_attrs = #fir.var_attrs<allocatable>} : (!fir.ref<!fir.type<_QFtest_derived_type_allocatable_map_operand_and_block_additionTone_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ %2 = fir.load %1 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ %c0_0 = arith.constant 0 : index
+ %3:3 = fir.box_dims %2, %c0_0 : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
+ %c1_9 = arith.constant 1 : index
+ %c0_1 = arith.constant 0 : index
+ %4:3 = fir.box_dims %2, %c0_1 : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
+ %c0_2 = arith.constant 0 : index
+ %5 = arith.subi %4#1, %c1_9 : index
+ %6 = omp.map.bounds lower_bound(%c0_2 : index) upper_bound(%5 : index) extent(%4#1 : index) stride(%4#2 : index) start_idx(%3#0 : index) {stride_in_bytes = true}
+ %c4 = arith.constant 4 : index
+ %7 = fir.coordinate_of %0#0, %c4 : (!fir.ref<!fir.type<_QFtest_derived_type_allocatable_map_operand_and_block_additionTone_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>, index) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ %8 = omp.map.info var_ptr(%7 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.box<!fir.heap<!fir.array<?xi32>>>) map_clauses(tofrom) capture(ByRef) bounds(%6) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>> {name = "one_l%array_j"}
+ %9 = omp.map.info var_ptr(%0#0 : !fir.ref<!fir.type<_QFtest_derived_type_allocatable_map_operand_and_block_additionTone_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>, !fir.type<_QFtest_derived_type_allocatable_map_operand_and_block_additionTone_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>) map_clauses(tofrom) capture(ByRef) members(%8 : [4] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.ref<!fir.type<_QFtest_derived_type_allocatable_map_operand_and_block_additionTone_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>> {name = "one_l", partial_map = true}
+ omp.target map_entries(%9 -> %arg1 : !fir.ref<!fir.type<_QFtest_derived_type_allocatable_map_operand_and_block_additionTone_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>) {
+ omp.terminator
+ }
+ return
+}
+
+// CHECK: func.func @dtype_alloca_op_block_add(%[[ARG0:.*]]: !fir.ref<[[REC_TY:!fir.type<_QFtest_derived_type_allocatable_map_operand_and_block_additionTone_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<\?xi32>>>,k:i32}]]>>) {
+// CHECK: %[[ALLOCA:.*]]:2 = hlfir.declare %[[ARG0]] {{.*}} : (!fir.ref<[[REC_TY]]>>) -> (!fir.ref<[[REC_TY]]>>, !fir.ref<[[REC_TY]]>>)
+// CHECK: %[[BOUNDS:.*]] = omp.map.bounds lower_bound(%{{.*}} : index) upper_bound(%{{.*}} : index) extent(%{{.*}} : index) stride(%{{.*}} : index) start_idx(%{{.*}} : index) {stride_in_bytes = true}
+// CHECK: %[[MEMBER_COORD:.*]] = fir.coordinate_of %[[ALLOCA]]#0, %{{.*}} : (!fir.ref<[[REC_TY]]>>, index) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+// CHECK: %[[MEMBER_BASE_ADDR:.*]] = fir.box_offset %[[MEMBER_COORD:.*]] base_addr : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>
+// CHECK: %[[MAP_MEMBER_BASE_ADDR:.*]] = omp.map.info var_ptr(%[[MEMBER_COORD]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.array<?xi32>) var_ptr_ptr(%[[MEMBER_BASE_ADDR]] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>> {{.*}}
+// CHECK: %[[MAP_MEMBER_DESCRIPTOR:.*]] = omp.map.info var_ptr(%[[MEMBER_COORD]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.box<!fir.heap<!fir.array<?xi32>>>) map_clauses(to) capture(ByRef) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>> {name = "one_l%array_j"}
+// CHECK: %[[MAP_MEMBER_PARENT:.*]] = omp.map.info var_ptr(%[[ALLOCA]]#0 : !fir.ref<[[REC_TY]]>>, [[REC_TY]]>) map_clauses(tofrom) capture(ByRef) members(%10, %9 : [4], [4, 0] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) -> !fir.ref<[[REC_TY]]>> {{.*}}
+// CHECK: omp.target map_entries(%[[MAP_MEMBER_DESCRIPTOR]] -> %[[ARG1:.*]], %[[MAP_MEMBER_BASE_ADDR]] -> %[[ARG2:.*]], %[[MAP_MEMBER_PARENT]] -> %[[ARG3:.*]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>, !fir.ref<[[REC_TY]]>>) {
+
+// -----
+
+func.func @alloca_dtype_map_op_block_add(%arg0 : !fir.ref<!fir.box<!fir.heap<!fir.type<_QFtest_allocatable_derived_type_map_operand_and_block_additionTone_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>>>) {
+ %0:2 = hlfir.declare %arg0 {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFtest_allocatable_derived_type_map_operand_and_block_additionEone_l"} : (!fir.ref<!fir.box<!fir.heap<!fir.type<_QFtest_allocatable_derived_type_map_operand_and_block_additionTone_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>>>) -> (!fir.ref<!fir.box<!fir.heap<!fir.type<_QFtest_allocatable_derived_type_map_operand_and_block_additionTone_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>>>, !fir.ref<!fir.box<!fir.heap<!fir.type<_QFtest_allocatable_derived_type_map_operand_and_block_additionTone_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>>>)
+ %1 = fir.load %0#0 : !fir.ref<!fir.box<!fir.heap<!fir.type<_QFtest_allocatable_derived_type_map_operand_and_block_additionTone_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>>>
+ %2 = fir.box_addr %1 : (!fir.box<!fir.heap<!fir.type<_QFtest_allocatable_derived_type_map_operand_and_block_additionTone_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>>) -> !fir.heap<!fir.type<_QFtest_allocatable_derived_type_map_operand_and_block_additionTone_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>
+ %3 = hlfir.designate %2{"array_j"} {fortran_attrs = #fir.var_attrs<allocatable>} : (!fir.heap<!fir.type<_QFtest_allocatable_derived_type_map_operand_and_block_additionTone_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ %4 = fir.load %3 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ %c0_0 = arith.constant 0 : index
+ %5:3 = fir.box_dims %4, %c0_0 : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
+ %c1_0 = arith.constant 1 : index
+ %c0_1 = arith.constant 0 : index
+ %6:3 = fir.box_dims %4, %c0_1 : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
+ %c0_2 = arith.constant 0 : index
+ %7 = arith.subi %6#1, %c1_0 : index
+ %8 = omp.map.bounds lower_bound(%c0_2 : index) upper_bound(%7 : index) extent(%6#1 : index) stride(%6#2 : index) start_idx(%5#0 : index) {stride_in_bytes = true}
+ %9 = fir.load %0#0 : !fir.ref<!fir.box<!fir.heap<!fir.type<_QFtest_allocatable_derived_type_map_operand_and_block_additionTone_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>>>
+ %c4 = arith.constant 4 : index
+ %10 = fir.coordinate_of %9, %c4 : (!fir.box<!fir.heap<!fir.type<_QFtest_allocatable_derived_type_map_operand_and_block_additionTone_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>>, index) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ %11 = omp.map.info var_ptr(%10 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.box<!fir.heap<!fir.array<?xi32>>>) map_clauses(tofrom) capture(ByRef) bounds(%8) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>> {name = "one_l%array_j"}
+ %12 = fir.load %0#0 : !fir.ref<!fir.box<!fir.heap<!fir.type<_QFtest_allocatable_derived_type_map_operand_and_block_additionTone_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>>>
+ %c5 = arith.constant 5 : index
+ %13 = fir.coordinate_of %12, %c5 : (!fir.box<!fir.heap<!fir.type<_QFtest_allocatable_derived_type_map_operand_and_block_additionTone_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>>, index) -> !fir.ref<i32>
+ %14 = omp.map.info var_ptr(%13 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32> {name = "one_l%k"}
+ %15 = omp.map.info var_ptr(%0#1 : !fir.ref<!fir.box<!fir.heap<!fir.type<_QFtest_allocatable_derived_type_map_operand_and_block_additionTone_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>>>, !fir.box<!fir.heap<!fir.type<_QFtest_allocatable_derived_type_map_operand_and_block_additionTone_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>>) map_clauses(tofrom) capture(ByRef) members(%11, %14 : [4], [5] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<i32>) -> !fir.ref<!fir.box<!fir.heap<!fir.type<_QFtest_allocatable_derived_type_map_operand_and_block_additionTone_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>>> {name = "one_l", partial_map = true}
+ omp.target map_entries(%15 -> %arg1 : !fir.ref<!fir.box<!fir.heap<!fir.type<_QFtest_allocatable_derived_type_map_operand_and_block_additionTone_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>>>) {
+ omp.terminator
+ }
+ return
+ }
+
+// CHECK: func.func @alloca_dtype_map_op_block_add(%[[ARG0:.*]]: !fir.ref<!fir.box<!fir.heap<!fir.type<[[REC_TY:_QFtest_allocatable_derived_type_map_operand_and_block_additionTone_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<\?xi32>>>,k:i32}]]>>>>) {
+// CHECK: %[[ALLOCA:.*]]:2 = hlfir.declare %[[ARG0]] {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFtest_allocatable_derived_type_map_operand_and_block_additionEone_l"} : (!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]]>>>>)
+// CHECK: %[[BOUNDS:.*]] = omp.map.bounds lower_bound(%{{.*}} : index) upper_bound(%{{.*}} : index) extent(%{{.*}}#1 : index) stride(%{{.*}}#2 : index) start_idx(%{{.*}}#0 : index) {stride_in_bytes = true}
+// CHECK: %[[LOAD_ALLOCA:.*]] = fir.load %[[ALLOCA]]#0 : !fir.ref<!fir.box<!fir.heap<!fir.type<[[REC_TY]]>>>>
+// CHECK: %[[ALLOCATABLE_MEMBER_COORD:.*]] = fir.coordinate_of %[[LOAD_ALLOCA]], %{{.*}} : (!fir.box<!fir.heap<!fir.type<[[REC_TY]]>>>, index) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+// CHECK: %[[ALLOCATABLE_MEMBER_BASE_ADDR:.*]] = fir.box_offset %[[ALLOCATABLE_MEMBER_COORD]] base_addr : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>
+// CHECK: %[[MAP_ALLOCA_MEMBER_BASE_ADDR:.*]] = omp.map.info var_ptr(%[[ALLOCATABLE_MEMBER_COORD]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.array<?xi32>) var_ptr_ptr(%[[ALLOCATABLE_MEMBER_BASE_ADDR]] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>> {{.*}}
+// CHECK: %[[MAP_ALLOCA_MEMBER_DESCRIPTOR:.*]] = omp.map.info var_ptr(%[[ALLOCATABLE_MEMBER_COORD]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.box<!fir.heap<!fir.array<?xi32>>>) map_clauses(to) capture(ByRef) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>> {{.*}}
+// CHECK: %[[LOAD_ALLOCA2:.*]] = fir.load %[[ALLOCA]]#0 : !fir.ref<!fir.box<!fir.heap<!fir.type<[[REC_TY]]>>>>
+// CHECK: %[[REGULAR_MEMBER_COORD:.*]] = fir.coordinate_of %[[LOAD_ALLOCA2]], %{{.*}} : (!fir.box<!fir.heap<!fir.type<[[REC_TY]]>>>, index) -> !fir.ref<i32>
+// CHECK: %[[MAP_REGULAR_MEMBER:.*]] = omp.map.info var_ptr(%[[REGULAR_MEMBER_COORD]] : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32> {{.*}}
+// 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]]>) var_ptr_ptr(%[[ALLOCATABLE_PARENT_BASE_ADDR]] : !fir.llvm_ptr<!fir.ref<!fir.type<[[REC_TY]]>>>) map_clauses(tofrom) capture(ByRef) -> !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(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_ALLOCA_PARENT_BASE_ADDR]] -> %[[ARG1:.*]], %[[MAP_ALLOCA_MEMBER_DESCRIPTOR]] -> %[[ARG2:.*]], %[[MAP_ALLOCA_MEMBER_BASE_ADDR]] -> %[[ARG3:.*]], %[[MAP_REGULAR_MEMBER]] -> %[[ARG4:.*]], %[[MAP_PARENT_DESCRIPTOR]] -> %[[ARG5:.*]] : !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]]>>>>) {
+
+// -----
+
+ func.func @alloca_nest_dtype_map_op_block_add(%arg0 : !fir.ref<!fir.box<!fir.heap<!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTtop_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>>>) {
+ %0:2 = hlfir.declare %arg0 {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFtest_alloca_nested_derived_type_map_operand_and_block_additionEone_l"} : (!fir.ref<!fir.box<!fir.heap<!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTtop_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>>>) -> (!fir.ref<!fir.box<!fir.heap<!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTtop_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>>>, !fir.ref<!fir.box<!fir.heap<!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTtop_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>>>)
+ %1 = fir.load %0#0 : !fir.ref<!fir.box<!fir.heap<!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTtop_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>>>
+ %2 = fir.box_addr %1 : (!fir.box<!fir.heap<!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTtop_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>>) -> !fir.heap<!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTtop_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>
+ %3 = hlfir.designate %2{"nest"} : (!fir.heap<!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTtop_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>) -> !fir.ref<!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>
+ %4 = hlfir.designate %3{"array_k"} {fortran_attrs = #fir.var_attrs<allocatable>} : (!fir.ref<!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ %5 = fir.load %4 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ %c0_0 = arith.constant 0 : index
+ %6:3 = fir.box_dims %5, %c0_0 : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
+ %c1_0 = arith.constant 1 : index
+ %c0_1 = arith.constant 0 : index
+ %7:3 = fir.box_dims %5, %c0_1 : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
+ %8 = arith.subi %7#1, %c1_0 : index
+ %9 = omp.map.bounds lower_bound(%c0_1 : index) upper_bound(%8 : index) extent(%7#1 : index) stride(%7#2 : index) start_idx(%6#0 : index) {stride_in_bytes = true}
+ %10 = fir.load %0#0 : !fir.ref<!fir.box<!fir.heap<!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTtop_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>>>
+ %c6 = arith.constant 6 : index
+ %11 = fir.coordinate_of %10, %c6 : (!fir.box<!fir.heap<!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTtop_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>>, index) -> !fir.ref<!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>
+ %c2_0 = arith.constant 2 : index
+ %12 = fir.coordinate_of %11, %c2_0 : (!fir.ref<!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>, index) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ %13 = omp.map.info var_ptr(%12 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.box<!fir.heap<!fir.array<?xi32>>>) map_clauses(tofrom) capture(ByRef) bounds(%9) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>> {name = "one_l%nest%array_k"}
+ %14 = fir.load %0#0 : !fir.ref<!fir.box<!fir.heap<!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTtop_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>>>
+ %15 = fir.coordinate_of %14, %c6 : (!fir.box<!fir.heap<!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTtop_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>>, index) -> !fir.ref<!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>
+ %c3 = arith.constant 3 : index
+ %16 = fir.coordinate_of %15, %c3 : (!fir.ref<!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>, index) -> !fir.ref<i32>
+ %17 = omp.map.info var_ptr(%16 : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32> {name = "one_l%nest%k"}
+ %18 = omp.map.info var_ptr(%0#1 : !fir.ref<!fir.box<!fir.heap<!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTtop_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>>>, !fir.box<!fir.heap<!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTtop_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>>) map_clauses(tofrom) capture(ByRef) members(%13, %17 : [6,2], [6,3] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<i32>) -> !fir.ref<!fir.box<!fir.heap<!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTtop_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>>> {name = "one_l", partial_map = true}
+ omp.target map_entries(%18 -> %arg1 : !fir.ref<!fir.box<!fir.heap<!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTtop_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>>>) {
+ omp.terminator
+ }
+ return
+ }
+
+// CHECK: func.func @alloca_nest_dtype_map_op_block_add(%[[ARG0:.*]]: !fir.ref<!fir.box<!fir.heap<!fir.type<[[REC_TY:_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTtop_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<\?xi32>>>,k:i32,nest:!fir.type<_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<\?xi32>>>,k:i32}>}]]>>>>) {
+// CHECK: %[[ALLOCA:.*]]: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]]>>>>)
+// CHECK: %[[BOUNDS:.*]] = omp.map.bounds lower_bound(%{{.*}} : index) upper_bound(%{{.*}} : index) extent(%{{.*}} : index) stride(%{{.*}} : index) start_idx(%{{.*}} : index) {stride_in_bytes = true}
+// CHECK: %[[ALLOCA_LOAD:.*]] = fir.load %[[ALLOCA]]#0 : !fir.ref<!fir.box<!fir.heap<!fir.type<[[REC_TY]]>>>>
+// CHECK: %[[INTERMEDIATE_DTYPE_NESTED_MEMBER:.*]] = fir.coordinate_of %[[ALLOCA_LOAD]], %{{.*}} : (!fir.box<!fir.heap<!fir.type<[[REC_TY]]>>>, index) -> !fir.ref<!fir.type<[[REC_TY2:_QFtest_alloca_nested_derived_type_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<\?xi32>>>,k:i32}]]>>
+// CHECK: %[[NESTED_ALLOCA_MEMBER:.*]] = fir.coordinate_of %[[INTERMEDIATE_DTYPE_NESTED_MEMBER]], %{{.*}} : (!fir.ref<!fir.type<[[REC_TY2]]>>, index) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+// CHECK: %[[NESTED_ALLOCA_MEMBER_BASE_ADDR:.*]] = fir.box_offset %[[NESTED_ALLOCA_MEMBER]] base_addr : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>
+// CHECK: %[[MAP_NESTED_ALLOCA_MEMBER_BASE_ADDR:.*]] = omp.map.info var_ptr(%[[NESTED_ALLOCA_MEMBER]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.array<?xi32>) var_ptr_ptr(%[[NESTED_ALLOCA_MEMBER_BASE_ADDR]] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>> {{.*}}
+// CHECK: %[[MAP_NESTED_ALLOCA_MEMBER:.*]] = omp.map.info var_ptr(%[[NESTED_ALLOCA_MEMBER]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.box<!fir.heap<!fir.array<?xi32>>>) map_clauses(to) capture(ByRef) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>> {{.*}}
+// CHECK: %[[ALLOCA_LOAD2:.*]] = fir.load %[[ALLOCA]]#0 : !fir.ref<!fir.box<!fir.heap<!fir.type<[[REC_TY]]>>>>
+// CHECK: %[[INTERMEDIATE_DTYPE_NESTED_MEMBER2:.*]] = fir.coordinate_of %[[ALLOCA_LOAD2]], %{{.*}} : (!fir.box<!fir.heap<!fir.type<[[REC_TY]]>>>, index) -> !fir.ref<!fir.type<[[REC_TY2]]>>
+// CHECK: %[[NESTED_REGULAR_MEMBER:.*]] = fir.coordinate_of %[[INTERMEDIATE_DTYPE_NESTED_MEMBER2]], %{{.*}} : (!fir.ref<!fir.type<[[REC_TY2]]>>, index) -> !fir.ref<i32>
+// CHECK: %[[MAP_NESTED_REGULAR_MEMBER:.*]] = omp.map.info var_ptr(%[[NESTED_REGULAR_MEMBER:.*]] : !fir.ref<i32>, i32) map_clauses(tofrom) capture(ByRef) -> !fir.ref<i32> {{.*}}
+// 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]]>) var_ptr_ptr(%[[ALLOCATABLE_PARENT_BASE_ADDR]] : !fir.llvm_ptr<!fir.ref<!fir.type<[[REC_TY]]>>>) map_clauses(tofrom) capture(ByRef) -> !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(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_BASE_ADDR]] -> %[[ARG1:.*]], %[[MAP_NESTED_ALLOCA_MEMBER]] -> %[[ARG2:.*]], %[[MAP_NESTED_ALLOCA_MEMBER_BASE_ADDR]] -> %[[ARG3:.*]], %[[MAP_NESTED_REGULAR_MEMBER]] -> %[[ARG4:.*]], %[[MAP_ALLOCATABLE_PARENT_DESCRIPTOR]] -> %[[ARG5:.*]] : !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]]>>>>) {
+
+// -----
+
+ func.func @nest_dtype_alloca_map_op_block_add(%arg0 : !fir.ref<!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTtop_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>) {
+ %0:2 = hlfir.declare %arg0 {uniq_name = "_QFtest_nested_derived_type_alloca_map_operand_and_block_additionEone_l"} : (!fir.ref<!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTtop_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>) -> (!fir.ref<!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTtop_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>, !fir.ref<!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTtop_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>)
+ %1 = hlfir.designate %0#0{"nest"} : (!fir.ref<!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTtop_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>) -> !fir.ref<!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>
+ %2 = hlfir.designate %1{"array_k"} {fortran_attrs = #fir.var_attrs<allocatable>} : (!fir.ref<!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ %3 = fir.load %2 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ %c0_0 = arith.constant 0 : index
+ %4:3 = fir.box_dims %3, %c0_0 : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
+ %c1_16 = arith.constant 1 : index
+ %c0_1 = arith.constant 0 : index
+ %5:3 = fir.box_dims %3, %c0_1 : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
+ %c0_18 = arith.constant 0 : index
+ %6 = arith.subi %5#1, %c1_16 : index
+ %7 = omp.map.bounds lower_bound(%c0_18 : index) upper_bound(%6 : index) extent(%5#1 : index) stride(%5#2 : index) start_idx(%4#0 : index) {stride_in_bytes = true}
+ %c6_0 = arith.constant 6 : index
+ %8 = fir.coordinate_of %0#0, %c6_0 : (!fir.ref<!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTtop_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>, index) -> !fir.ref<!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>
+ %c2_0 = arith.constant 2 : index
+ %9 = fir.coordinate_of %8, %c2_0 : (!fir.ref<!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>>, index) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ %10 = omp.map.info var_ptr(%9 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.box<!fir.heap<!fir.array<?xi32>>>) map_clauses(tofrom) capture(ByRef) bounds(%7) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>> {name = "one_l%nest%array_k"}
+ %11 = omp.map.info var_ptr(%0#0 : !fir.ref<!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTtop_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>, !fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTtop_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>) map_clauses(tofrom) capture(ByRef) members(%10 : [6,2] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.ref<!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTtop_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>> {name = "one_l", partial_map = true}
+ omp.target map_entries(%11 -> %arg1 : !fir.ref<!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTtop_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<?xi32>>>,k:i32}>}>>) {
+ omp.terminator
+ }
+ return
+ }
+
+// CHECK: func.func @nest_dtype_alloca_map_op_block_add(%[[ARG0:.*]]: !fir.ref<!fir.type<[[REC_TY:_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTtop_layer{i:f32,scalar:!fir.box<!fir.heap<i32>>,array_i:!fir.array<10xi32>,j:f32,array_j:!fir.box<!fir.heap<!fir.array<\?xi32>>>,k:i32,nest:!fir.type<_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<\?xi32>>>,k:i32}>}]]>>) {
+// CHECK: %[[ALLOCA:.*]]:2 = hlfir.declare %[[ARG0]] {{.*}} : (!fir.ref<!fir.type<[[REC_TY]]>>) -> (!fir.ref<!fir.type<[[REC_TY]]>>, !fir.ref<!fir.type<[[REC_TY]]>>)
+// CHECK: %[[BOUNDS:.*]] = omp.map.bounds lower_bound(%{{.*}} : index) upper_bound(%{{.*}} : index) extent(%{{.*}} : index) stride(%{{.*}} : index) start_idx(%{{.*}} : index) {stride_in_bytes = true}
+// CHECK: %[[NESTED_DTYPE_COORD:.*]] = fir.coordinate_of %[[ALLOCA]]#0, %{{.*}} : (!fir.ref<!fir.type<[[REC_TY]]>>, index) -> !fir.ref<!fir.type<[[REC_TY2:_QFtest_nested_derived_type_alloca_map_operand_and_block_additionTmiddle_layer{i:f32,array_i:!fir.array<10xi32>,array_k:!fir.box<!fir.heap<!fir.array<\?xi32>>>,k:i32}]]>>
+// CHECK: %[[ALLOCATABLE_MEMBER:.*]] = fir.coordinate_of %[[NESTED_DTYPE_COORD]], %{{.*}} : (!fir.ref<!fir.type<[[REC_TY2]]>>, index) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+// CHECK: %[[ALLOCATABLE_MEMBER_BASE_ADDR:.*]] = fir.box_offset %[[ALLOCATABLE_MEMBER]] base_addr : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>
+// CHECK: %[[MAP_ALLOCATABLE_MEMBER_BASE_ADDR:.*]] = omp.map.info var_ptr(%[[ALLOCATABLE_MEMBER]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.array<?xi32>) var_ptr_ptr(%[[ALLOCATABLE_MEMBER_BASE_ADDR]] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) map_clauses(tofrom) capture(ByRef) bounds(%[[BOUNDS]]) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>> {{.*}}
+// CHECK: %[[MAP_ALLOCATABLE_MEMBER_DESCRIPTOR:.*]] = omp.map.info var_ptr(%[[ALLOCATABLE_MEMBER]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.box<!fir.heap<!fir.array<?xi32>>>) map_clauses(to) capture(ByRef) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>> {{.*}}
+// CHECK: %[[MAP_PARENT:.*]] = omp.map.info var_ptr(%[[ALLOCA]]#0 : !fir.ref<!fir.type<[[REC_TY]]>>, !fir.type<[[REC_TY]]>) map_clauses(tofrom) capture(ByRef) members(%12, %11 : [6, 2], [6, 2, 0] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) -> !fir.ref<!fir.type<[[REC_TY]]>> {{.*}}
+// CHECK: omp.target map_entries(%[[MAP_ALLOCATABLE_MEMBER_DESCRIPTOR]] -> %[[ARG1:.*]], %[[MAP_ALLOCATABLE_MEMBER_BASE_ADDR]] -> %[[ARG2:.*]], %[[MAP_PARENT]] -> %[[ARG3:.*]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>, !fir.ref<!fir.type<[[REC_TY]]>>) {
+
+// -----
+
+ func.func @nest_dtype_mem_idx(%arg0 : !fir.ref<!fir.type<_QFmaptype_nested_derived_type_member_idxTdtype{i:f32,vertexes:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QFmaptype_nested_derived_type_member_idxTvertexes{test:i32,vertexx:!fir.box<!fir.heap<!fir.array<?xi32>>>,vertexy:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>>>,array_i:!fir.array<10xi32>}>>) {
+ %0:2 = hlfir.declare %arg0 {uniq_name = "_QFmaptype_nested_derived_type_member_idxEalloca_dtype"} : (!fir.ref<!fir.type<_QFmaptype_nested_derived_type_member_idxTdtype{i:f32,vertexes:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QFmaptype_nested_derived_type_member_idxTvertexes{test:i32,vertexx:!fir.box<!fir.heap<!fir.array<?xi32>>>,vertexy:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>>>,array_i:!fir.array<10xi32>}>>) -> (!fir.ref<!fir.type<_QFmaptype_nested_derived_type_member_idxTdtype{i:f32,vertexes:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QFmaptype_nested_derived_type_member_idxTvertexes{test:i32,vertexx:!fir.box<!fir.heap<!fir.array<?xi32>>>,vertexy:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>>>,array_i:!fir.array<10xi32>}>>, !fir.ref<!fir.type<_QFmaptype_nested_derived_type_member_idxTdtype{i:f32,vertexes:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QFmaptype_nested_derived_type_member_idxTvertexes{test:i32,vertexx:!fir.box<!fir.heap<!fir.array<?xi32>>>,vertexy:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>>>,array_i:!fir.array<10xi32>}>>)
+ %c1_15 = arith.constant 1 : index
+ %1 = omp.map.bounds lower_bound(%c1_15 : index) upper_bound(%c1_15 : index) extent(%c1_15 : index) stride(%c1_15 : index) start_idx(%c1_15 : index) {stride_in_bytes = true}
+ %2 = fir.coordinate_of %0#0, %c1_15 : (!fir.ref<!fir.type<_QFmaptype_nested_derived_type_member_idxTdtype{i:f32,vertexes:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QFmaptype_nested_derived_type_member_idxTvertexes{test:i32,vertexx:!fir.box<!fir.heap<!fir.array<?xi32>>>,vertexy:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>>>,array_i:!fir.array<10xi32>}>>, index) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.type<_QFmaptype_nested_derived_type_member_idxTvertexes{test:i32,vertexx:!fir.box<!fir.heap<!fir.array<?xi32>>>,vertexy:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>>>>
+ %3 = omp.map.bounds lower_bound(%c1_15 : index) upper_bound(%c1_15 : index) extent(%c1_15 : index) stride(%c1_15 : index) start_idx(%c1_15 : index) {stride_in_bytes = true}
+ %4 = omp.map.info var_ptr(%2 : !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.type<_QFmaptype_nested_derived_type_member_idxTvertexes{test:i32,vertexx:!fir.box<!fir.heap<!fir.array<?xi32>>>,vertexy:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>>>>, !fir.box<!fir.heap<!fir.array<?x!fir.type<_QFmaptype_nested_derived_type_member_idxTvertexes{test:i32,vertexx:!fir.box<!fir.heap<!fir.array<?xi32>>>,vertexy:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>>>) map_clauses(exit_release_or_enter_alloc) capture(ByRef) bounds(%3) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.type<_QFmaptype_nested_derived_type_member_idxTvertexes{test:i32,vertexx:!fir.box<!fir.heap<!fir.array<?xi32>>>,vertexy:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>>>> {name = "alloca_dtype%vertexes(2_8)%vertexy"}
+ %5 = fir.load %2 : !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.type<_QFmaptype_nested_derived_type_member_idxTvertexes{test:i32,vertexx:!fir.box<!fir.heap<!fir.array<?xi32>>>,vertexy:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>>>>
+ %c2_i64 = arith.constant 2 : i64
+ %c1_20 = arith.constant 1 : index
+ %6 = fir.convert %c2_i64 : (i64) -> index
+ %7 = arith.subi %6, %c1_20 : index
+ %8 = fir.coordinate_of %5, %7 : (!fir.box<!fir.heap<!fir.array<?x!fir.type<_QFmaptype_nested_derived_type_member_idxTvertexes{test:i32,vertexx:!fir.box<!fir.heap<!fir.array<?xi32>>>,vertexy:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>>>, index) -> !fir.ref<!fir.type<_QFmaptype_nested_derived_type_member_idxTvertexes{test:i32,vertexx:!fir.box<!fir.heap<!fir.array<?xi32>>>,vertexy:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>
+ %c2_21 = arith.constant 2 : index
+ %9 = fir.coordinate_of %8, %c2_21 : (!fir.ref<!fir.type<_QFmaptype_nested_derived_type_member_idxTvertexes{test:i32,vertexx:!fir.box<!fir.heap<!fir.array<?xi32>>>,vertexy:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>, index) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+ %10 = omp.map.info var_ptr(%9 : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.box<!fir.heap<!fir.array<?xi32>>>) map_clauses(tofrom) capture(ByRef) bounds(%1) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>> {name = "alloca_dtype%vertexes(2_8)%vertexy"}
+ %11 = omp.map.info var_ptr(%0#1 : !fir.ref<!fir.type<_QFmaptype_nested_derived_type_member_idxTdtype{i:f32,vertexes:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QFmaptype_nested_derived_type_member_idxTvertexes{test:i32,vertexx:!fir.box<!fir.heap<!fir.array<?xi32>>>,vertexy:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>>>,array_i:!fir.array<10xi32>}>>, !fir.type<_QFmaptype_nested_derived_type_member_idxTdtype{i:f32,vertexes:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QFmaptype_nested_derived_type_member_idxTvertexes{test:i32,vertexx:!fir.box<!fir.heap<!fir.array<?xi32>>>,vertexy:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>>>,array_i:!fir.array<10xi32>}>) map_clauses(exit_release_or_enter_alloc) capture(ByRef) members(%4, %10 : [1], [1,2] : !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.type<_QFmaptype_nested_derived_type_member_idxTvertexes{test:i32,vertexx:!fir.box<!fir.heap<!fir.array<?xi32>>>,vertexy:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.ref<!fir.type<_QFmaptype_nested_derived_type_member_idxTdtype{i:f32,vertexes:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QFmaptype_nested_derived_type_member_idxTvertexes{test:i32,vertexx:!fir.box<!fir.heap<!fir.array<?xi32>>>,vertexy:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>>>,array_i:!fir.array<10xi32>}>> {name = "alloca_dtype", partial_map = true}
+ omp.target map_entries(%11 -> %arg1 : !fir.ref<!fir.type<_QFmaptype_nested_derived_type_member_idxTdtype{i:f32,vertexes:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QFmaptype_nested_derived_type_member_idxTvertexes{test:i32,vertexx:!fir.box<!fir.heap<!fir.array<?xi32>>>,vertexy:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>>>,array_i:!fir.array<10xi32>}>>) {
+ omp.terminator
+ }
+ return
+ }
+
+// CHECK: func.func @nest_dtype_mem_idx(%[[ARG0:.*]]: !fir.ref<!fir.type<[[REC_TY:_QFmaptype_nested_derived_type_member_idxTdtype{i:f32,vertexes:!fir.box<!fir.heap<!fir.array<\?x!fir.type<_QFmaptype_nested_derived_type_member_idxTvertexes{test:i32,vertexx:!fir.box<!fir.heap<!fir.array<\?xi32>>>,vertexy:!fir.box<!fir.heap<!fir.array<\?xi32>>>}>>>>,array_i:!fir.array<10xi32>}]]>>) {
+// CHECK: %[[DECLARE:.*]]:2 = hlfir.declare %[[ARG0]] {{.*}} : (!fir.ref<!fir.type<[[REC_TY]]>>) -> (!fir.ref<!fir.type<[[REC_TY]]>>, !fir.ref<!fir.type<[[REC_TY]]>>)
+// CHECK: %[[DESC_1:.*]] = fir.coordinate_of %[[DECLARE]]#0, %{{.*}} : (!fir.ref<!fir.type<[[REC_TY]]>>, index) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.type<[[REC_TY2:_QFmaptype_nested_derived_type_member_idxTvertexes{test:i32,vertexx:!fir.box<!fir.heap<!fir.array<\?xi32>>>,vertexy:!fir.box<!fir.heap<!fir.array<\?xi32>>>}]]>>>>>
+// CHECK: %[[BASE_ADDR_1:.*]] = fir.box_offset %[[DESC_1]] base_addr : (!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]]>>>>
+// CHECK: %[[BASE_ADDR_MAP_1:.*]] = omp.map.info var_ptr(%[[DESC_1]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.type<[[REC_TY2]]>>>>>, !fir.array<?x!fir.type<[[REC_TY2]]>>) var_ptr_ptr(%[[BASE_ADDR_1]] : !fir.llvm_ptr<!fir.ref<!fir.array<?x!fir.type<[[REC_TY2]]>>>>) map_clauses(exit_release_or_enter_alloc) capture(ByRef) bounds(%{{.*}}) -> !fir.llvm_ptr<!fir.ref<!fir.array<?x!fir.type<[[REC_TY2]]>>>> {{.*}}
+// CHECK: %[[DESC_MAP_1:.*]] = omp.map.info var_ptr(%[[DESC_1]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.type<[[REC_TY2]]>>>>>, !fir.box<!fir.heap<!fir.array<?x!fir.type<[[REC_TY2]]>>>>) map_clauses(to) capture(ByRef) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.type<[[REC_TY2]]>>>>> {{.*}}
+// CHECK: %[[DESC_LD_1:.*]] = fir.load %[[DESC_1]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.type<[[REC_TY2]]>>>>>
+// CHECK: %[[MEMBER_ACCESS_1:.*]] = fir.coordinate_of %[[DESC_LD_1]], %{{.*}} : (!fir.box<!fir.heap<!fir.array<?x!fir.type<[[REC_TY2]]>>>>, index) -> !fir.ref<!fir.type<[[REC_TY2]]>>
+// CHECK: %[[DESC_2:.*]] = fir.coordinate_of %[[MEMBER_ACCESS_1]], %{{.*}} : (!fir.ref<!fir.type<[[REC_TY2]]>>, index) -> !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+// CHECK: %[[BASE_ADDR_2:.*]] = fir.box_offset %[[DESC_2]] base_addr : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>
+// CHECK: %[[BASE_ADDR_MAP_2:.*]] = omp.map.info var_ptr(%[[DESC_2]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.array<?xi32>) var_ptr_ptr(%[[BASE_ADDR_2]] : !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>) map_clauses(tofrom) capture(ByRef) 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(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(exit_release_or_enter_alloc) 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(%[[DESC_MAP_1]] -> %{{.*}}, %[[BASE_ADDR_MAP_1]] -> %{{.*}}, %[[DESC_MAP_2]] -> %{{.*}}, %[[BASE_ADDR_MAP_2]] -> %{{.*}}, %[[TOP_PARENT_MAP]] -> %{{.*}} : !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]]>>) {
More information about the llvm-branch-commits
mailing list