[flang-commits] [flang] [flang][OpenMP] Reuse canonical default mapper names for nested mappings - fix issue #210402 (PR #212251)
via flang-commits
flang-commits at lists.llvm.org
Wed Aug 12 03:31:22 PDT 2026
https://github.com/laoshd updated https://github.com/llvm/llvm-project/pull/212251
>From 88d7dd49a00d078de3c3556fa8b8207343e9458b Mon Sep 17 00:00:00 2001
From: Shandong Lao <shandong.lao at hpe.com>
Date: Mon, 27 Jul 2026 08:13:51 -0500
Subject: [PATCH 1/6] [flang][OpenMP] Reuse canonical default mapper names for
nested mappings
---
flang/include/flang/Utils/OpenMP.h | 5 ++
.../OpenMP/DoConcurrentConversion.cpp | 3 +-
flang/lib/Utils/OpenMP.cpp | 25 +++++++++-
...mapper-explicit-default-nested-pointer.f90 | 46 +++++++++++++++++++
4 files changed, 76 insertions(+), 3 deletions(-)
create mode 100644 flang/test/Lower/OpenMP/declare-mapper-explicit-default-nested-pointer.f90
diff --git a/flang/include/flang/Utils/OpenMP.h b/flang/include/flang/Utils/OpenMP.h
index e8627347fd578..0cb77e25af947 100644
--- a/flang/include/flang/Utils/OpenMP.h
+++ b/flang/include/flang/Utils/OpenMP.h
@@ -64,6 +64,11 @@ void cloneOrMapRegionOutsiders(
using RecordMemberMapperMangler =
std::function<void(std::string &mapperId, llvm::StringRef memberName)>;
+/// Build the canonical symbol name for a derived type's default mapper from
+/// the FIR record type. This matches the compiler-generated name shape used by
+/// explicit default declare mapper lowering.
+std::string getCanonicalDefaultDeclareMapperName(fir::RecordType recordType);
+
mlir::FlatSymbolRefAttr getOrGenImplicitDefaultDeclareMapper(
fir::FirOpBuilder &firOpBuilder, mlir::Location loc,
fir::RecordType recordType, llvm::StringRef mapperNameStr,
diff --git a/flang/lib/Optimizer/OpenMP/DoConcurrentConversion.cpp b/flang/lib/Optimizer/OpenMP/DoConcurrentConversion.cpp
index 945250daf1dbe..b50f5ccf6a323 100644
--- a/flang/lib/Optimizer/OpenMP/DoConcurrentConversion.cpp
+++ b/flang/lib/Optimizer/OpenMP/DoConcurrentConversion.cpp
@@ -621,7 +621,8 @@ class DoConcurrentConversion
mlir::FlatSymbolRefAttr mapperId;
if (requiresImplcitMapper) {
std::string mapperIdName =
- recordType.getName().str() + llvm::omp::OmpDefaultMapperName;
+ Fortran::utils::openmp::getCanonicalDefaultDeclareMapperName(
+ recordType);
// TODO Add a mangler callback once nested record types are supported.
mapperId = Fortran::utils::openmp::getOrGenImplicitDefaultDeclareMapper(
builder, liveIn.getLoc(), recordType, mapperIdName);
diff --git a/flang/lib/Utils/OpenMP.cpp b/flang/lib/Utils/OpenMP.cpp
index 9c22cc950e3f7..ebc5062eb39f0 100644
--- a/flang/lib/Utils/OpenMP.cpp
+++ b/flang/lib/Utils/OpenMP.cpp
@@ -13,11 +13,33 @@
#include "flang/Optimizer/Builder/FIRBuilder.h"
#include "flang/Optimizer/Dialect/FIROps.h"
#include "flang/Optimizer/Dialect/FIRType.h"
+#include "flang/Optimizer/Support/InternalNames.h"
#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
#include "mlir/Transforms/RegionUtils.h"
namespace Fortran::utils::openmp {
+std::string getCanonicalDefaultDeclareMapperName(fir::RecordType recordType) {
+ auto [kind, deconstructed] =
+ fir::NameUniquer::deconstruct(recordType.getName());
+ if (kind != fir::NameUniquer::NameKind::DERIVED_TYPE)
+ return recordType.getName().str() + llvm::omp::OmpDefaultMapperName;
+
+ llvm::SmallVector<llvm::StringRef> modules;
+ llvm::SmallVector<llvm::StringRef> procs;
+ modules.reserve(deconstructed.modules.size());
+ procs.reserve(deconstructed.procs.size());
+ for (const std::string &module : deconstructed.modules)
+ modules.emplace_back(module);
+ for (const std::string &proc : deconstructed.procs) {
+ procs.emplace_back(proc);
+ }
+
+ std::string mapperName = deconstructed.name + llvm::omp::OmpDefaultMapperName;
+ return fir::NameUniquer::doGenerated(
+ modules, procs, deconstructed.blockId, mapperName);
+}
+
mlir::omp::MapInfoOp createMapInfoOp(mlir::OpBuilder &builder,
mlir::Location loc, mlir::Value baseAddr, mlir::Value varPtrPtr,
llvm::StringRef name, llvm::ArrayRef<mlir::Value> bounds,
@@ -260,8 +282,7 @@ mlir::FlatSymbolRefAttr getOrGenImplicitDefaultDeclareMapper(
mlir::FlatSymbolRefAttr mapperId;
if (auto recType = mlir::dyn_cast<fir::RecordType>(
fir::getFortranElementType(memberType))) {
- std::string mapperIdName =
- recType.getName().str() + llvm::omp::OmpDefaultMapperName;
+ std::string mapperIdName = getCanonicalDefaultDeclareMapperName(recType);
mangler(mapperIdName, memberName);
mapperId = getOrGenImplicitDefaultDeclareMapper(
firOpBuilder, loc, recType, mapperIdName, mangler);
diff --git a/flang/test/Lower/OpenMP/declare-mapper-explicit-default-nested-pointer.f90 b/flang/test/Lower/OpenMP/declare-mapper-explicit-default-nested-pointer.f90
new file mode 100644
index 0000000000000..9c41cbb0a00b2
--- /dev/null
+++ b/flang/test/Lower/OpenMP/declare-mapper-explicit-default-nested-pointer.f90
@@ -0,0 +1,46 @@
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %s -o - | FileCheck %s
+!
+! Test that when an explicit default DECLARE MAPPER is defined for a type (newdata)
+! whose only component is a pointer, and that type is used as an allocatable component
+! of another type (newvec), the compiler-generated implicit mapper for newvec correctly
+! references the user-defined mapper for newdata rather than synthesising a new
+! implicit one that would silently skip the pointer component.
+!
+! An explicit `map(s)` on a newvec variable is the code-path that triggers implicit
+! mapper generation for newvec (unlike an implicit target capture, which suppresses
+! mapper generation for plain non-allocatable/non-pointer derived types).
+
+module m
+ type :: newdata
+ real(8), pointer :: value
+ end type
+ !$omp declare mapper(default: newdata :: v) map(tofrom: v%value)
+
+ type :: newvec
+ integer :: len
+ type(newdata), allocatable :: data(:)
+ end type
+end module
+
+program main
+ use m
+ implicit none
+ type(newvec) :: s
+
+ ! Explicit map(s) triggers implicit mapper generation for newvec.
+ !$omp target data map(s)
+ s%len = 0
+ !$omp end target data
+end program
+
+! The user-defined default mapper for newdata must have tofrom map for v%value.
+! CHECK-DAG: omp.declare_mapper @_QQMmnewdata_omp_default_mapper
+! CHECK-DAG: map_clauses(tofrom)
+! CHECK-DAG: {name = "v%value"}
+
+! The implicit default mapper for newvec must reference the user-defined newdata
+! mapper by its canonical name. Before the fix this referenced a separately-
+! synthesised bogus mapper (@_QMmTnewdata_omp_default_mapper) that had no maps
+! for pointer components, causing a null-address device fault at runtime.
+! CHECK-DAG: omp.declare_mapper @_QQMmnewvec_omp_default_mapper
+! CHECK-DAG: mapper(@_QQMmnewdata_omp_default_mapper)
\ No newline at end of file
>From 63da3e7b443ac77aaf15ed0fbce7b01696162551 Mon Sep 17 00:00:00 2001
From: Shandong Lao <shandong.lao at hpe.com>
Date: Mon, 27 Jul 2026 12:41:15 -0500
Subject: [PATCH 2/6] [flang][OpenMP] Preserve PDT kinds in implicit mapper
canonical names
---
flang/lib/Utils/OpenMP.cpp | 16 ++++++++-
...lare-mapper-implicit-default-pdt-kinds.f90 | 35 +++++++++++++++++++
2 files changed, 50 insertions(+), 1 deletion(-)
create mode 100644 flang/test/Lower/OpenMP/declare-mapper-implicit-default-pdt-kinds.f90
diff --git a/flang/lib/Utils/OpenMP.cpp b/flang/lib/Utils/OpenMP.cpp
index ebc5062eb39f0..4023c8bd21542 100644
--- a/flang/lib/Utils/OpenMP.cpp
+++ b/flang/lib/Utils/OpenMP.cpp
@@ -20,6 +20,18 @@
namespace Fortran::utils::openmp {
std::string getCanonicalDefaultDeclareMapperName(fir::RecordType recordType) {
+ auto appendKinds = [](std::string &name,
+ llvm::ArrayRef<std::int64_t> kinds) {
+ for (std::int64_t kind : kinds) {
+ name.append("K");
+ if (kind < 0) {
+ name.append("N");
+ kind = -kind;
+ }
+ name.append(std::to_string(kind));
+ }
+ };
+
auto [kind, deconstructed] =
fir::NameUniquer::deconstruct(recordType.getName());
if (kind != fir::NameUniquer::NameKind::DERIVED_TYPE)
@@ -35,7 +47,9 @@ std::string getCanonicalDefaultDeclareMapperName(fir::RecordType recordType) {
procs.emplace_back(proc);
}
- std::string mapperName = deconstructed.name + llvm::omp::OmpDefaultMapperName;
+ std::string mapperName = deconstructed.name;
+ appendKinds(mapperName, deconstructed.kinds);
+ mapperName.append(llvm::omp::OmpDefaultMapperName);
return fir::NameUniquer::doGenerated(
modules, procs, deconstructed.blockId, mapperName);
}
diff --git a/flang/test/Lower/OpenMP/declare-mapper-implicit-default-pdt-kinds.f90 b/flang/test/Lower/OpenMP/declare-mapper-implicit-default-pdt-kinds.f90
new file mode 100644
index 0000000000000..7deea93f07930
--- /dev/null
+++ b/flang/test/Lower/OpenMP/declare-mapper-implicit-default-pdt-kinds.f90
@@ -0,0 +1,35 @@
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %s -o - | FileCheck %s
+!
+! Check that implicit default mapper generation does not alias parameterized
+! derived type instantiations with different kind parameters.
+! Before the fix both pdt(4) and pdt(8) nested mappings could bind to the same
+! mapper symbol due to kind-less name canonicalization.
+
+module m
+ type :: pdt(k)
+ integer, kind :: k
+ real(k) :: x
+ end type
+
+ type :: holder4
+ type(pdt(4)), allocatable :: a(:)
+ end type
+
+ type :: holder8
+ type(pdt(8)), allocatable :: a(:)
+ end type
+contains
+ subroutine s(h4, h8)
+ type(holder4) :: h4
+ type(holder8) :: h8
+ !$omp target data map(h4, h8)
+ !$omp end target data
+ end subroutine
+end module
+
+! CHECK-DAG: omp.declare_mapper @_QQMmpdtK4_omp_default_mapper
+! CHECK-DAG: omp.declare_mapper @_QQMmpdtK8_omp_default_mapper
+! CHECK-DAG: omp.declare_mapper @_QQMmholder4_omp_default_mapper
+! CHECK-DAG: omp.declare_mapper @_QQMmholder8_omp_default_mapper
+! CHECK-DAG: mapper(@_QQMmpdtK4_omp_default_mapper)
+! CHECK-DAG: mapper(@_QQMmpdtK8_omp_default_mapper)
>From f9914d7dc364bafa5f22bf91b9a2b9fca1c3ea13 Mon Sep 17 00:00:00 2001
From: Shandong Lao <shandong.lao at hpe.com>
Date: Mon, 27 Jul 2026 13:09:15 -0500
Subject: [PATCH 3/6] Update code format
---
flang/lib/Utils/OpenMP.cpp | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/flang/lib/Utils/OpenMP.cpp b/flang/lib/Utils/OpenMP.cpp
index 4023c8bd21542..9c64dd52ce84e 100644
--- a/flang/lib/Utils/OpenMP.cpp
+++ b/flang/lib/Utils/OpenMP.cpp
@@ -20,8 +20,7 @@
namespace Fortran::utils::openmp {
std::string getCanonicalDefaultDeclareMapperName(fir::RecordType recordType) {
- auto appendKinds = [](std::string &name,
- llvm::ArrayRef<std::int64_t> kinds) {
+ auto appendKinds = [](std::string &name, llvm::ArrayRef<std::int64_t> kinds) {
for (std::int64_t kind : kinds) {
name.append("K");
if (kind < 0) {
>From 2008807d25dee6665656a832ceeaca395015d3d8 Mon Sep 17 00:00:00 2001
From: Shandong Lao <shandong.lao at hpe.com>
Date: Wed, 29 Jul 2026 18:31:39 -0500
Subject: [PATCH 4/6] [flang][OpenMP] Reuse explicit default mappers for PDT
nested mapping
---
flang/lib/Utils/OpenMP.cpp | 33 +++++++++++++++
...er-implicit-default-pdt-explicit-reuse.f90 | 41 +++++++++++++++++++
2 files changed, 74 insertions(+)
create mode 100644 flang/test/Lower/OpenMP/declare-mapper-implicit-default-pdt-explicit-reuse.f90
diff --git a/flang/lib/Utils/OpenMP.cpp b/flang/lib/Utils/OpenMP.cpp
index 9c64dd52ce84e..0d01af8b96aaf 100644
--- a/flang/lib/Utils/OpenMP.cpp
+++ b/flang/lib/Utils/OpenMP.cpp
@@ -209,6 +209,29 @@ mlir::FlatSymbolRefAttr getOrGenImplicitDefaultDeclareMapper(
fir::FirOpBuilder &firOpBuilder, mlir::Location loc,
fir::RecordType recordType, llvm::StringRef mapperNameStr,
RecordMemberMapperMangler mangler) {
+ auto getKindlessDefaultMapperName =
+ [](fir::RecordType recType) -> std::string {
+ auto [nameKind, deconstructed] =
+ fir::NameUniquer::deconstruct(recType.getName());
+ if (nameKind != fir::NameUniquer::NameKind::DERIVED_TYPE ||
+ deconstructed.kinds.empty())
+ return {};
+
+ llvm::SmallVector<llvm::StringRef> modules;
+ llvm::SmallVector<llvm::StringRef> procs;
+ modules.reserve(deconstructed.modules.size());
+ procs.reserve(deconstructed.procs.size());
+ for (const std::string &module : deconstructed.modules)
+ modules.emplace_back(module);
+ for (const std::string &proc : deconstructed.procs)
+ procs.emplace_back(proc);
+
+ std::string mapperName =
+ deconstructed.name + llvm::omp::OmpDefaultMapperName;
+ return fir::NameUniquer::doGenerated(
+ modules, procs, deconstructed.blockId, mapperName);
+ };
+
if (mapperNameStr.empty())
return {};
@@ -217,6 +240,16 @@ mlir::FlatSymbolRefAttr getOrGenImplicitDefaultDeclareMapper(
return mlir::FlatSymbolRefAttr::get(
firOpBuilder.getContext(), mapperNameStr);
+ if (std::string kindlessMapperName =
+ getKindlessDefaultMapperName(recordType);
+ !kindlessMapperName.empty() && kindlessMapperName != mapperNameStr) {
+ if (auto explicitMapper = moduleOp.lookupSymbol<mlir::omp::DeclareMapperOp>(
+ kindlessMapperName);
+ explicitMapper && explicitMapper.getType() == recordType)
+ return mlir::FlatSymbolRefAttr::get(
+ firOpBuilder.getContext(), kindlessMapperName);
+ }
+
mlir::OpBuilder::InsertionGuard guard(firOpBuilder);
firOpBuilder.setInsertionPointToStart(moduleOp.getBody());
diff --git a/flang/test/Lower/OpenMP/declare-mapper-implicit-default-pdt-explicit-reuse.f90 b/flang/test/Lower/OpenMP/declare-mapper-implicit-default-pdt-explicit-reuse.f90
new file mode 100644
index 0000000000000..fe4395254a61f
--- /dev/null
+++ b/flang/test/Lower/OpenMP/declare-mapper-implicit-default-pdt-explicit-reuse.f90
@@ -0,0 +1,41 @@
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %s -o - | FileCheck %s
+!
+! Check that nested implicit default mapper generation for PDT components reuses
+! an explicit default declare mapper(default:) when available for that exact
+! instantiated type.
+
+module m
+ type :: pdt(k)
+ integer, kind :: k
+ real(k) :: x
+ end type
+
+ !$omp declare mapper(default: pdt(4) :: v) map(tofrom: v%x)
+
+ type :: holder4
+ type(pdt(4)), allocatable :: a(:)
+ end type
+
+ type :: holder8
+ type(pdt(8)), allocatable :: a(:)
+ end type
+contains
+ subroutine s(h4, h8)
+ type(holder4) :: h4
+ type(holder8) :: h8
+ !$omp target data map(h4, h8)
+ !$omp end target data
+ end subroutine
+end module
+
+! Explicit mapper for pdt(4) keeps the historical kindless symbol spelling.
+! CHECK-DAG: omp.declare_mapper @_QQMmpdt_omp_default_mapper : !fir.type<_QMmTpdtK4
+
+! Implicit mapper for pdt(8) remains distinct and kind-qualified.
+! CHECK-DAG: omp.declare_mapper @_QQMmpdtK8_omp_default_mapper : !fir.type<_QMmTpdtK8
+
+! holder4 nested mapping must reuse the explicit pdt(4) mapper, not synthesize
+! a pdtK4 implicit default mapper.
+! CHECK-DAG: mapper(@_QQMmpdt_omp_default_mapper)
+! CHECK-DAG: mapper(@_QQMmpdtK8_omp_default_mapper)
+! CHECK-NOT: omp.declare_mapper @_QQMmpdtK4_omp_default_mapper
>From 59322202d521f6acf007b4d23c00ec022491b1bf Mon Sep 17 00:00:00 2001
From: Shandong Lao <shandong.lao at hpe.com>
Date: Thu, 30 Jul 2026 10:30:23 -0500
Subject: [PATCH 5/6] Update code format; Consolidate the three test files into
one.
---
flang/lib/Utils/OpenMP.cpp | 3 +-
...mapper-explicit-default-nested-pointer.f90 | 46 ----------
...are-mapper-implicit-default-nested-pdt.f90 | 86 +++++++++++++++++++
...er-implicit-default-pdt-explicit-reuse.f90 | 41 ---------
...lare-mapper-implicit-default-pdt-kinds.f90 | 35 --------
5 files changed, 87 insertions(+), 124 deletions(-)
delete mode 100644 flang/test/Lower/OpenMP/declare-mapper-explicit-default-nested-pointer.f90
create mode 100644 flang/test/Lower/OpenMP/declare-mapper-implicit-default-nested-pdt.f90
delete mode 100644 flang/test/Lower/OpenMP/declare-mapper-implicit-default-pdt-explicit-reuse.f90
delete mode 100644 flang/test/Lower/OpenMP/declare-mapper-implicit-default-pdt-kinds.f90
diff --git a/flang/lib/Utils/OpenMP.cpp b/flang/lib/Utils/OpenMP.cpp
index 0d01af8b96aaf..0d7954f2e4838 100644
--- a/flang/lib/Utils/OpenMP.cpp
+++ b/flang/lib/Utils/OpenMP.cpp
@@ -240,8 +240,7 @@ mlir::FlatSymbolRefAttr getOrGenImplicitDefaultDeclareMapper(
return mlir::FlatSymbolRefAttr::get(
firOpBuilder.getContext(), mapperNameStr);
- if (std::string kindlessMapperName =
- getKindlessDefaultMapperName(recordType);
+ if (std::string kindlessMapperName = getKindlessDefaultMapperName(recordType);
!kindlessMapperName.empty() && kindlessMapperName != mapperNameStr) {
if (auto explicitMapper = moduleOp.lookupSymbol<mlir::omp::DeclareMapperOp>(
kindlessMapperName);
diff --git a/flang/test/Lower/OpenMP/declare-mapper-explicit-default-nested-pointer.f90 b/flang/test/Lower/OpenMP/declare-mapper-explicit-default-nested-pointer.f90
deleted file mode 100644
index 9c41cbb0a00b2..0000000000000
--- a/flang/test/Lower/OpenMP/declare-mapper-explicit-default-nested-pointer.f90
+++ /dev/null
@@ -1,46 +0,0 @@
-! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %s -o - | FileCheck %s
-!
-! Test that when an explicit default DECLARE MAPPER is defined for a type (newdata)
-! whose only component is a pointer, and that type is used as an allocatable component
-! of another type (newvec), the compiler-generated implicit mapper for newvec correctly
-! references the user-defined mapper for newdata rather than synthesising a new
-! implicit one that would silently skip the pointer component.
-!
-! An explicit `map(s)` on a newvec variable is the code-path that triggers implicit
-! mapper generation for newvec (unlike an implicit target capture, which suppresses
-! mapper generation for plain non-allocatable/non-pointer derived types).
-
-module m
- type :: newdata
- real(8), pointer :: value
- end type
- !$omp declare mapper(default: newdata :: v) map(tofrom: v%value)
-
- type :: newvec
- integer :: len
- type(newdata), allocatable :: data(:)
- end type
-end module
-
-program main
- use m
- implicit none
- type(newvec) :: s
-
- ! Explicit map(s) triggers implicit mapper generation for newvec.
- !$omp target data map(s)
- s%len = 0
- !$omp end target data
-end program
-
-! The user-defined default mapper for newdata must have tofrom map for v%value.
-! CHECK-DAG: omp.declare_mapper @_QQMmnewdata_omp_default_mapper
-! CHECK-DAG: map_clauses(tofrom)
-! CHECK-DAG: {name = "v%value"}
-
-! The implicit default mapper for newvec must reference the user-defined newdata
-! mapper by its canonical name. Before the fix this referenced a separately-
-! synthesised bogus mapper (@_QMmTnewdata_omp_default_mapper) that had no maps
-! for pointer components, causing a null-address device fault at runtime.
-! CHECK-DAG: omp.declare_mapper @_QQMmnewvec_omp_default_mapper
-! CHECK-DAG: mapper(@_QQMmnewdata_omp_default_mapper)
\ No newline at end of file
diff --git a/flang/test/Lower/OpenMP/declare-mapper-implicit-default-nested-pdt.f90 b/flang/test/Lower/OpenMP/declare-mapper-implicit-default-nested-pdt.f90
new file mode 100644
index 0000000000000..84e98523cd7b9
--- /dev/null
+++ b/flang/test/Lower/OpenMP/declare-mapper-implicit-default-nested-pdt.f90
@@ -0,0 +1,86 @@
+! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %s -o - | FileCheck %s
+!
+! This file groups related OpenMP mapper-name regressions:
+! 1) nested default mapper reuse for pointer components
+! 2) distinct implicit mapper names for PDT kind instantiations
+! 3) nested PDT reuse of an explicit declare mapper(default:)
+
+module ptr_case
+ type :: newdata
+ real(8), pointer :: value
+ end type
+ !$omp declare mapper(default: newdata :: v) map(tofrom: v%value)
+
+ type :: newvec
+ integer :: len
+ type(newdata), allocatable :: data(:)
+ end type
+contains
+ subroutine trigger
+ type(newvec) :: s
+ !$omp target data map(s)
+ s%len = 0
+ !$omp end target data
+ end subroutine
+end module
+
+! CHECK-DAG: omp.declare_mapper @{{.*}}newdata_omp_default_mapper
+! CHECK-DAG: map_clauses(tofrom)
+! CHECK-DAG: {name = "v%value"}
+! CHECK-DAG: omp.declare_mapper @{{.*}}newvec_omp_default_mapper
+! CHECK-DAG: mapper(@{{.*}}newdata_omp_default_mapper)
+
+module kinds_case
+ type :: pdt(k)
+ integer, kind :: k
+ real(k) :: x
+ end type
+
+ type :: holder4_kinds
+ type(pdt(4)), allocatable :: a(:)
+ end type
+
+ type :: holder8_kinds
+ type(pdt(8)), allocatable :: a(:)
+ end type
+contains
+ subroutine trigger
+ type(holder4_kinds) :: h4
+ type(holder8_kinds) :: h8
+ !$omp target data map(h4, h8)
+ !$omp end target data
+ end subroutine
+end module
+
+! CHECK-DAG: omp.declare_mapper @{{.*}}pdtK4_omp_default_mapper
+! CHECK-DAG: omp.declare_mapper @{{.*}}pdtK8_omp_default_mapper
+! CHECK-DAG: mapper(@{{.*}}pdtK4_omp_default_mapper)
+! CHECK-DAG: mapper(@{{.*}}pdtK8_omp_default_mapper)
+
+module reuse_case
+ type :: pdt(k)
+ integer, kind :: k
+ real(k) :: x
+ end type
+
+ !$omp declare mapper(default: pdt(4) :: v) map(tofrom: v%x)
+
+ type :: holder4_reuse
+ type(pdt(4)), allocatable :: a(:)
+ end type
+
+ type :: holder8_reuse
+ type(pdt(8)), allocatable :: a(:)
+ end type
+contains
+ subroutine trigger
+ type(holder4_reuse) :: h4
+ type(holder8_reuse) :: h8
+ !$omp target data map(h4, h8)
+ !$omp end target data
+ end subroutine
+end module
+
+! CHECK-DAG: omp.declare_mapper @{{.*}}pdt_omp_default_mapper : !fir.type<{{.*}}TpdtK4
+! CHECK-DAG: mapper(@{{.*}}pdt_omp_default_mapper)
+! CHECK-DAG: mapper(@{{.*}}pdtK8_omp_default_mapper)
diff --git a/flang/test/Lower/OpenMP/declare-mapper-implicit-default-pdt-explicit-reuse.f90 b/flang/test/Lower/OpenMP/declare-mapper-implicit-default-pdt-explicit-reuse.f90
deleted file mode 100644
index fe4395254a61f..0000000000000
--- a/flang/test/Lower/OpenMP/declare-mapper-implicit-default-pdt-explicit-reuse.f90
+++ /dev/null
@@ -1,41 +0,0 @@
-! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %s -o - | FileCheck %s
-!
-! Check that nested implicit default mapper generation for PDT components reuses
-! an explicit default declare mapper(default:) when available for that exact
-! instantiated type.
-
-module m
- type :: pdt(k)
- integer, kind :: k
- real(k) :: x
- end type
-
- !$omp declare mapper(default: pdt(4) :: v) map(tofrom: v%x)
-
- type :: holder4
- type(pdt(4)), allocatable :: a(:)
- end type
-
- type :: holder8
- type(pdt(8)), allocatable :: a(:)
- end type
-contains
- subroutine s(h4, h8)
- type(holder4) :: h4
- type(holder8) :: h8
- !$omp target data map(h4, h8)
- !$omp end target data
- end subroutine
-end module
-
-! Explicit mapper for pdt(4) keeps the historical kindless symbol spelling.
-! CHECK-DAG: omp.declare_mapper @_QQMmpdt_omp_default_mapper : !fir.type<_QMmTpdtK4
-
-! Implicit mapper for pdt(8) remains distinct and kind-qualified.
-! CHECK-DAG: omp.declare_mapper @_QQMmpdtK8_omp_default_mapper : !fir.type<_QMmTpdtK8
-
-! holder4 nested mapping must reuse the explicit pdt(4) mapper, not synthesize
-! a pdtK4 implicit default mapper.
-! CHECK-DAG: mapper(@_QQMmpdt_omp_default_mapper)
-! CHECK-DAG: mapper(@_QQMmpdtK8_omp_default_mapper)
-! CHECK-NOT: omp.declare_mapper @_QQMmpdtK4_omp_default_mapper
diff --git a/flang/test/Lower/OpenMP/declare-mapper-implicit-default-pdt-kinds.f90 b/flang/test/Lower/OpenMP/declare-mapper-implicit-default-pdt-kinds.f90
deleted file mode 100644
index 7deea93f07930..0000000000000
--- a/flang/test/Lower/OpenMP/declare-mapper-implicit-default-pdt-kinds.f90
+++ /dev/null
@@ -1,35 +0,0 @@
-! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 %s -o - | FileCheck %s
-!
-! Check that implicit default mapper generation does not alias parameterized
-! derived type instantiations with different kind parameters.
-! Before the fix both pdt(4) and pdt(8) nested mappings could bind to the same
-! mapper symbol due to kind-less name canonicalization.
-
-module m
- type :: pdt(k)
- integer, kind :: k
- real(k) :: x
- end type
-
- type :: holder4
- type(pdt(4)), allocatable :: a(:)
- end type
-
- type :: holder8
- type(pdt(8)), allocatable :: a(:)
- end type
-contains
- subroutine s(h4, h8)
- type(holder4) :: h4
- type(holder8) :: h8
- !$omp target data map(h4, h8)
- !$omp end target data
- end subroutine
-end module
-
-! CHECK-DAG: omp.declare_mapper @_QQMmpdtK4_omp_default_mapper
-! CHECK-DAG: omp.declare_mapper @_QQMmpdtK8_omp_default_mapper
-! CHECK-DAG: omp.declare_mapper @_QQMmholder4_omp_default_mapper
-! CHECK-DAG: omp.declare_mapper @_QQMmholder8_omp_default_mapper
-! CHECK-DAG: mapper(@_QQMmpdtK4_omp_default_mapper)
-! CHECK-DAG: mapper(@_QQMmpdtK8_omp_default_mapper)
>From 5c335b2fcc5d79ad08cfa76e6607d8ea1fde1cba Mon Sep 17 00:00:00 2001
From: Shandong Lao <shandong.lao at hpe.com>
Date: Wed, 12 Aug 2026 05:28:44 -0500
Subject: [PATCH 6/6] [flang][OpenMP] I210402: Fix direct PDT default-mapper
naming and add regression
Fix direct PDT default mapper ID construction to be kind-aware in OpenMP
lowering paths so direct mappings of pdt(4)/pdt(8) do not alias to the same
mapper symbol.
Also extend the consolidated OpenMP mapper regression to cover the direct-PDT
case and tighten checks to avoid cross-matching in a grouped test file.
---
flang/lib/Lower/OpenMP/OpenMP.cpp | 12 +++++++--
flang/lib/Lower/OpenMP/Utils.cpp | 11 ++++++--
...are-mapper-implicit-default-nested-pdt.f90 | 27 +++++++++++++++----
3 files changed, 41 insertions(+), 9 deletions(-)
diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index 9807023935784..ebde2e8b4f299 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -3989,8 +3989,16 @@ genTargetOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
const semantics::DerivedTypeSpec *typeSpec =
sym.GetType() ? sym.GetType()->AsDerived() : nullptr;
if (typeSpec) {
- std::string mapperIdName =
- typeSpec->name().ToString() + llvm::omp::OmpDefaultMapperName;
+ std::string mapperIdName;
+ if (auto recordType = mlir::dyn_cast_or_null<fir::RecordType>(
+ converter.genType(*typeSpec))) {
+ mapperIdName =
+ Fortran::utils::openmp::getCanonicalDefaultDeclareMapperName(
+ recordType);
+ } else {
+ mapperIdName =
+ typeSpec->name().ToString() + llvm::omp::OmpDefaultMapperName;
+ }
if (auto *mapperSym =
converter.getCurrentScope().FindSymbol(mapperIdName))
mapperIdName = converter.mangleName(
diff --git a/flang/lib/Lower/OpenMP/Utils.cpp b/flang/lib/Lower/OpenMP/Utils.cpp
index 8f57f00d59c58..15926ff26c1fd 100644
--- a/flang/lib/Lower/OpenMP/Utils.cpp
+++ b/flang/lib/Lower/OpenMP/Utils.cpp
@@ -1094,8 +1094,15 @@ getDefaultMapperID(Fortran::lower::AbstractConverter &converter,
!typeSpec)
return {};
- std::string mapperIdName =
- typeSpec->name().ToString() + llvm::omp::OmpDefaultMapperName;
+ std::string mapperIdName;
+ if (auto recordType = mlir::dyn_cast_or_null<fir::RecordType>(
+ converter.genType(*typeSpec))) {
+ mapperIdName = Fortran::utils::openmp::getCanonicalDefaultDeclareMapperName(
+ recordType);
+ } else {
+ mapperIdName =
+ typeSpec->name().ToString() + llvm::omp::OmpDefaultMapperName;
+ }
if (auto *sym = converter.getCurrentScope().FindSymbol(mapperIdName)) {
mapperIdName =
converter.mangleName(mapperIdName, sym->GetUltimate().owner());
diff --git a/flang/test/Lower/OpenMP/declare-mapper-implicit-default-nested-pdt.f90 b/flang/test/Lower/OpenMP/declare-mapper-implicit-default-nested-pdt.f90
index 84e98523cd7b9..2be4e8a1fe12e 100644
--- a/flang/test/Lower/OpenMP/declare-mapper-implicit-default-nested-pdt.f90
+++ b/flang/test/Lower/OpenMP/declare-mapper-implicit-default-nested-pdt.f90
@@ -52,10 +52,8 @@ subroutine trigger
end subroutine
end module
-! CHECK-DAG: omp.declare_mapper @{{.*}}pdtK4_omp_default_mapper
-! CHECK-DAG: omp.declare_mapper @{{.*}}pdtK8_omp_default_mapper
-! CHECK-DAG: mapper(@{{.*}}pdtK4_omp_default_mapper)
-! CHECK-DAG: mapper(@{{.*}}pdtK8_omp_default_mapper)
+! CHECK-DAG: omp.declare_mapper @{{.*}}kinds_casepdtK4_omp_default_mapper : !fir.type<{{.*}}TpdtK4
+! CHECK-DAG: omp.declare_mapper @{{.*}}kinds_casepdtK8_omp_default_mapper : !fir.type<{{.*}}TpdtK8
module reuse_case
type :: pdt(k)
@@ -83,4 +81,23 @@ subroutine trigger
! CHECK-DAG: omp.declare_mapper @{{.*}}pdt_omp_default_mapper : !fir.type<{{.*}}TpdtK4
! CHECK-DAG: mapper(@{{.*}}pdt_omp_default_mapper)
-! CHECK-DAG: mapper(@{{.*}}pdtK8_omp_default_mapper)
+! CHECK-DAG: mapper(@{{.*}}reuse_casepdtK8_omp_default_mapper)
+
+module direct_pdt_case
+ type :: direct_pdt(k)
+ integer, kind :: k
+ real(k), allocatable :: a(:)
+ end type
+contains
+ subroutine trigger
+ type(direct_pdt(4)) :: h4
+ type(direct_pdt(8)) :: h8
+ !$omp target data map(h4, h8)
+ !$omp end target data
+ end subroutine
+end module
+
+! CHECK-DAG: omp.declare_mapper @{{.*}}direct_pdtK4_omp_default_mapper : !fir.type<{{.*}}Tdirect_pdtK4
+! CHECK-DAG: omp.declare_mapper @{{.*}}direct_pdtK8_omp_default_mapper : !fir.type<{{.*}}Tdirect_pdtK8
+! CHECK-DAG: mapper(@{{.*}}direct_pdtK4_omp_default_mapper)
+! CHECK-DAG: mapper(@{{.*}}direct_pdtK8_omp_default_mapper)
More information about the flang-commits
mailing list