diff --git a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp index 5e194dc715d59..4921a1990b6e8 100644 --- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp @@ -4089,11 +4089,30 @@ static llvm::omp::OpenMPOffloadMappingFlags mapParentWithMembers( assert(!ompBuilder.Config.isTargetDevice() && "function only supported for host device codegen"); - // Map the first segment of our structure - combinedInfo.Types.emplace_back( + // Map the first segment of the parent. If a user-defined mapper is attached, + // include the parent's to/from-style bits (and common modifiers) in this + // base entry so the mapper receives correct copy semantics via its 'type' + // parameter. Also keep TARGET_PARAM when required for kernel arguments. + llvm::omp::OpenMPOffloadMappingFlags baseFlag = isTargetParams ? llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_TARGET_PARAM - : llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_NONE); + : llvm::omp::OpenMPOffloadMappingFlags::OMP_MAP_NONE; + + // Detect if this mapping uses a user-defined mapper. + bool hasUserMapper = mapData.Mappers[mapDataIndex] != nullptr; + if (hasUserMapper) { + using mapFlags = llvm::omp::OpenMPOffloadMappingFlags; + // Preserve relevant map-type bits from the parent clause. These include + // the copy direction (TO/FROM), as well as commonly used modifiers that + // should be visible to the mapper for correct behaviour. + mapFlags parentFlags = mapData.Types[mapDataIndex]; + mapFlags preserve = mapFlags::OMP_MAP_TO | mapFlags::OMP_MAP_FROM | + mapFlags::OMP_MAP_ALWAYS | mapFlags::OMP_MAP_CLOSE | + mapFlags::OMP_MAP_PRESENT | mapFlags::OMP_MAP_OMPX_HOLD; + baseFlag |= (parentFlags & preserve); + } + + combinedInfo.Types.emplace_back(baseFlag); combinedInfo.DevicePointers.emplace_back( mapData.DevicePointers[mapDataIndex]); combinedInfo.Mappers.emplace_back(mapData.Mappers[mapDataIndex]); diff --git a/offload/test/offloading/fortran/target-declare-mapper-allocatable.f90 b/offload/test/offloading/fortran/target-declare-mapper-allocatable.f90 new file mode 100644 index 0000000000000..d8d5e1b5631a5 --- /dev/null +++ b/offload/test/offloading/fortran/target-declare-mapper-allocatable.f90 @@ -0,0 +1,48 @@ +! This test validates that declare mapper for a derived type with an +! allocatable component preserves TO/FROM semantics for the component, +! ensuring the payload is copied back to the host on target exit. + +! REQUIRES: flang, amdgpu + +! RUN: %libomptarget-compile-fortran-run-and-check-generic + +program target_declare_mapper_allocatable + implicit none + + type :: real_t + real, allocatable :: real_arr(:) + end type real_t + + ! Map the allocatable array payload via a named mapper. + !$omp declare mapper (xyz : real_t :: t) map(tofrom: t%real_arr) + + type(real_t) :: r + integer :: i + logical :: ok + + allocate(r%real_arr(10)) + r%real_arr = 1.0 + + !$omp target map(mapper(xyz), tofrom: r) + do i = 1, size(r%real_arr) + r%real_arr(i) = 3.0 + end do + !$omp end target + + ok = .true. + do i = 1, size(r%real_arr) + if (r%real_arr(i) /= 3.0) ok = .false. + end do + if (ok) then + print *, "Test passed!" + else + print *, "Test failed!" + do i = 1, size(r%real_arr) + print *, r%real_arr(i) + end do + end if + + deallocate(r%real_arr) +end program target_declare_mapper_allocatable + +! CHECK: Test passed!