[flang-commits] [flang] 5bb2565 - [Flang][OpenMP] Generate maps for allocatable components of privatized symbols for target offload (#214015)

via flang-commits flang-commits at lists.llvm.org
Mon Aug 10 15:05:04 PDT 2026


Author: agozillon
Date: 2026-08-11T00:04:59+02:00
New Revision: 5bb2565693f062a9e99929db1814a7a076d4dc76

URL: https://github.com/llvm/llvm-project/commit/5bb2565693f062a9e99929db1814a7a076d4dc76
DIFF: https://github.com/llvm/llvm-project/commit/5bb2565693f062a9e99929db1814a7a076d4dc76.diff

LOG: [Flang][OpenMP] Generate maps for allocatable components of privatized symbols for target offload (#214015)

Currently we do not generate maps for allocatable components of derived
types for privatized derived type symbols, this can be a problem when
the variable requires initialization from the original copy, as the
device will try to perform initialization and the data will not be
present to do so. This causes a runtime memory access error on device.
Some example code that can trigger this:

type :: btype
    real(kind=8),allocatable, dimension(:) :: a
end type

!$omp target teams distribute parallel do firstprivate(b)

This does not apply to pointers as they aren't mandated to be
initialized as allocatables are at the moment I believe when they're
sub-objects. But it does apply to allocatables where initialization and
copy blocks are generated.

The fix in this PR is simply to utilize the existing default implicit
mapper generation infrastructure to populate a full mapping of all
allocatable components in a derived type, similar to the existing method
in the DoConcurrent pass.

Added: 
    

Modified: 
    flang/lib/Optimizer/OpenMP/MapsForPrivatizedSymbols.cpp
    flang/test/Transforms/omp-maps-for-privatized-symbols.fir

Removed: 
    


################################################################################
diff  --git a/flang/lib/Optimizer/OpenMP/MapsForPrivatizedSymbols.cpp b/flang/lib/Optimizer/OpenMP/MapsForPrivatizedSymbols.cpp
index a18f0c5a4186f..de3dd8d352b3b 100644
--- a/flang/lib/Optimizer/OpenMP/MapsForPrivatizedSymbols.cpp
+++ b/flang/lib/Optimizer/OpenMP/MapsForPrivatizedSymbols.cpp
@@ -29,12 +29,14 @@
 #include "flang/Optimizer/Dialect/Support/KindMapping.h"
 #include "flang/Optimizer/HLFIR/HLFIROps.h"
 #include "flang/Optimizer/OpenMP/Passes.h"
+#include "flang/Utils/OpenMP.h"
 
 #include "mlir/Dialect/Func/IR/FuncOps.h"
 #include "mlir/Dialect/OpenMP/OpenMPDialect.h"
 #include "mlir/IR/BuiltinAttributes.h"
 #include "mlir/IR/SymbolTable.h"
 #include "mlir/Pass/Pass.h"
+#include "llvm/Frontend/OpenMP/OMPConstants.h"
 #include "llvm/Support/Debug.h"
 
 #define DEBUG_TYPE "omp-maps-for-privatized-symbols"
@@ -123,6 +125,27 @@ class MapsForPrivatizedSymbolsPass
     else
       mapFlag = mlir::omp::ClauseMapFlags::to | mlir::omp::ClauseMapFlags::from;
 
+    mlir::FlatSymbolRefAttr mapperId = mlir::FlatSymbolRefAttr();
+    auto recordType = mlir::dyn_cast_or_null<fir::RecordType>(
+        fir::getFortranElementType(varType));
+    // TODO: Extend implicit mapper generation here and in
+    // DoConcurrentConversion to appropriately reuse the default implicit
+    // mapper for a type if it exists, this name mangling is not identical
+    // to the initial lowering, so it will generate a secondary identical
+    // mapper with a 
diff erent name mangling in certain cases. This could
+    // be done by changing the frontend naming to utilise the record type
+    // rather than the specification type when creating a name, avoiding
+    // the subtle 
diff erence in names or having separate postfixes for
+    // user defined default mappers and compiler generated default mappers
+    // and then searching if the type has a prexisting compiler generated
+    // default mapper to utilise in place of creating a new one.
+    if (recordType && fir::isRecordWithAllocatableMember(recordType)) {
+      std::string mapperName =
+          recordType.getName().str() + llvm::omp::OmpDefaultMapperName;
+      mapperId = Fortran::utils::openmp::getOrGenImplicitDefaultDeclareMapper(
+          builder, loc, recordType, mapperName);
+    }
+
     return omp::MapInfoOp::create(
         builder, loc, varType, varPtr,
         TypeAttr::get(
@@ -133,7 +156,7 @@ class MapsForPrivatizedSymbolsPass
         /*members=*/SmallVector<Value>{},
         /*member_index=*/mlir::ArrayAttr{},
         /*bounds=*/boundsOps,
-        /*mapperId=*/mlir::FlatSymbolRefAttr(), /*name=*/StringAttr(),
+        /*mapperId=*/mapperId, /*name=*/StringAttr(),
         builder.getBoolAttr(false));
   }
   void addMapInfoOp(omp::TargetOp targetOp, omp::MapInfoOp mapInfoOp) {

diff  --git a/flang/test/Transforms/omp-maps-for-privatized-symbols.fir b/flang/test/Transforms/omp-maps-for-privatized-symbols.fir
index 6669f0981cb90..82dfadaec437c 100644
--- a/flang/test/Transforms/omp-maps-for-privatized-symbols.fir
+++ b/flang/test/Transforms/omp-maps-for-privatized-symbols.fir
@@ -32,6 +32,49 @@ module attributes {omp.is_target_device = false} {
   }
 }
 // CHECK: %[[MAP0:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref<i32>, i32) map_clauses(to) capture(ByRef) -> !fir.ref<i32> {name = "a"}
-// CHECK: %[[MAP1:.*]] =  omp.map.info var_ptr({{.*}} : !fir.ref<!fir.box<!fir.heap<i32>>>, !fir.box<!fir.heap<i32>>) map_clauses(tofrom) capture(ByRef) -> !fir.ref<!fir.box<!fir.heap<i32>>>
+// CHECK: %[[MAP1:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref<!fir.box<!fir.heap<i32>>>, !fir.box<!fir.heap<i32>>) map_clauses(tofrom) capture(ByRef) -> !fir.ref<!fir.box<!fir.heap<i32>>>
 // CHECK: %[[MAP2:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref<i32>, i32) map_clauses(to) capture(ByCopy) -> !fir.ref<i32>
 // CHECK:  omp.target kernel_type(generic) map_entries(%[[MAP0]] -> %arg0, %[[MAP1]] -> %arg1, %[[MAP2]] -> %arg2 : !fir.ref<i32>, !fir.ref<!fir.box<!fir.heap<i32>>>, !fir.ref<i32>)
+
+// -----
+
+module attributes {omp.is_target_device = false} {
+  omp.private {type = private} @_QFtarget_genEdt_private : !fir.type<_QFTgen_t{x:!fir.box<!fir.heap<!fir.array<?xi32>>>}> init {
+  ^bb0(%arg0: !fir.ref<!fir.type<_QFTgen_t{x:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>, %arg1: !fir.ref<!fir.type<_QFTgen_t{x:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>):
+    %mold = fir.load %arg0 : !fir.ref<!fir.type<_QFTgen_t{x:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>
+    omp.yield(%arg1 : !fir.ref<!fir.type<_QFTgen_t{x:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>)
+  }
+  func.func @_QPtarget_gen() {
+    %0 = fir.alloca !fir.type<_QFTgen_t{x:!fir.box<!fir.heap<!fir.array<?xi32>>>}> {bindc_name = "dt", uniq_name = "_QFtarget_genEdt"}
+    %1:2 = hlfir.declare %0 {uniq_name = "_QFtarget_genEdt"} : (!fir.ref<!fir.type<_QFTgen_t{x:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>) -> (!fir.ref<!fir.type<_QFTgen_t{x:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>, !fir.ref<!fir.type<_QFTgen_t{x:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>)
+    omp.target kernel_type(generic) private(@_QFtarget_genEdt_private %1#0 -> %arg0 : !fir.ref<!fir.type<_QFTgen_t{x:!fir.box<!fir.heap<!fir.array<?xi32>>>}>>) {
+      omp.terminator
+    }
+    return
+  }
+}
+// CHECK: omp.declare_mapper @[[GEN_MAPPER:_QFTgen_t_omp_default_mapper]]
+// CHECK: %[[GEN_MAP:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref<!fir.type<_QFTgen_t{{.*}}>>, !fir.type<_QFTgen_t{{.*}}>) map_clauses(tofrom) capture(ByRef) mapper(@[[GEN_MAPPER]]) -> !fir.ref<!fir.type<_QFTgen_t{{.*}}>>
+// CHECK: omp.target kernel_type(generic) map_entries(%[[GEN_MAP]] -> %arg0 : !fir.ref<!fir.type<_QFTgen_t{{.*}}>>)
+
+// -----
+
+module attributes {omp.is_target_device = false} {
+  omp.private {type = private} @_QFtarget_plainEdt_private : !fir.type<_QFTplain_t{x:i32,y:f32}> init {
+  ^bb0(%arg0: !fir.ref<!fir.type<_QFTplain_t{x:i32,y:f32}>>, %arg1: !fir.ref<!fir.type<_QFTplain_t{x:i32,y:f32}>>):
+    %mold = fir.load %arg0 : !fir.ref<!fir.type<_QFTplain_t{x:i32,y:f32}>>
+    omp.yield(%arg1 : !fir.ref<!fir.type<_QFTplain_t{x:i32,y:f32}>>)
+  }
+  func.func @_QPtarget_plain() {
+    %0 = fir.alloca !fir.type<_QFTplain_t{x:i32,y:f32}> {bindc_name = "dt", uniq_name = "_QFtarget_plainEdt"}
+    %1:2 = hlfir.declare %0 {uniq_name = "_QFtarget_plainEdt"} : (!fir.ref<!fir.type<_QFTplain_t{x:i32,y:f32}>>) -> (!fir.ref<!fir.type<_QFTplain_t{x:i32,y:f32}>>, !fir.ref<!fir.type<_QFTplain_t{x:i32,y:f32}>>)
+    omp.target kernel_type(generic) private(@_QFtarget_plainEdt_private %1#0 -> %arg0 : !fir.ref<!fir.type<_QFTplain_t{x:i32,y:f32}>>) {
+      omp.terminator
+    }
+    return
+  }
+}
+
+// CHECK-NOT: omp.declare_mapper @_QFTplain_t_omp_default_mapper
+// CHECK: %[[PLAIN_MAP:.*]] = omp.map.info var_ptr({{.*}} : !fir.ref<!fir.type<_QFTplain_t{{.*}}>>, !fir.type<_QFTplain_t{{.*}}>) map_clauses(tofrom) capture(ByRef) -> !fir.ref<!fir.type<_QFTplain_t{{.*}}>>
+// CHECK-NOT: mapper(


        


More information about the flang-commits mailing list