[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
Mon Jul 27 06:43:14 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-flang-fir-hlfir

Author: laoshd

<details>
<summary>Changes</summary>

Summary
Fix issue #<!-- -->210402: [FLANG][OMP] flang compiled application failed with core dumped at Kernel 'omp target in _QQmain @ 28 (__omp_offloading_3a_5aca0b86__QQmain_l28)' -- Flang OpenMP nested implicit default-mapper naming so it reuses the same canonical symbol naming scheme as explicit declare mapper(default: ...) lowering.

Problem
For nested derived types, implicit mapper generation could derive a mapper symbol from FIR record names that did not match the explicit mapper naming path. That mismatch could create a second synthesized mapper, skip intended pointer-component mapping behavior, and lead to runtime offload faults.

Changes
Add a canonical mapper-name helper: getCanonicalDefaultDeclareMapperName(fir::RecordType)
Use canonical naming in nested implicit mapper generation paths: OpenMP utility mapper generation
DoConcurrent OpenMP conversion mapper path
Add regression test: declare-mapper-explicit-default-nested-pointer.f90

Result
Nested implicit mapper generation now consistently reuses user-defined default mappers by canonical symbol name, avoiding mismatched duplicate mapper creation and preventing the observed offload failure scenario.

---
Full diff: https://github.com/llvm/llvm-project/pull/212251.diff


4 Files Affected:

- (modified) flang/include/flang/Utils/OpenMP.h (+5) 
- (modified) flang/lib/Optimizer/OpenMP/DoConcurrentConversion.cpp (+2-1) 
- (modified) flang/lib/Utils/OpenMP.cpp (+23-2) 
- (added) flang/test/Lower/OpenMP/declare-mapper-explicit-default-nested-pointer.f90 (+46) 


``````````diff
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

``````````

</details>


https://github.com/llvm/llvm-project/pull/212251


More information about the flang-commits mailing list