[flang-commits] [flang] [flang][acc] Support sizing array of derived type for openacc mapping (PR #222404)

Razvan Lupusoru via flang-commits flang-commits at lists.llvm.org
Wed Sep 9 10:49:13 PDT 2026


https://github.com/razvanlupusoru updated https://github.com/llvm/llvm-project/pull/222404

>From 0007c018c0de0d233b83d675109daed441b1ac6f Mon Sep 17 00:00:00 2001
From: Razvan Lupusoru <rlupusoru at nvidia.com>
Date: Wed, 9 Sep 2026 10:41:09 -0700
Subject: [PATCH 1/2] [flang][acc] Support sizing array of derived type for
 openacc mapping

Adds support for array of derived type - tested both for mapping and
privatization. Now acc.map_info can be generated for this.
---
 .../OpenACC/Transforms/ACCMapInfoPrep.cpp     | 82 +++++++++++--------
 .../acc-fir-map-info-prep-privatize.mlir      | 28 +++++++
 .../Fir/OpenACC/acc-fir-map-info-prep.mlir    | 30 +++++++
 3 files changed, 107 insertions(+), 33 deletions(-)

diff --git a/flang/lib/Optimizer/OpenACC/Transforms/ACCMapInfoPrep.cpp b/flang/lib/Optimizer/OpenACC/Transforms/ACCMapInfoPrep.cpp
index 4ba5cc8b2d909..9f32f9d6a9360 100644
--- a/flang/lib/Optimizer/OpenACC/Transforms/ACCMapInfoPrep.cpp
+++ b/flang/lib/Optimizer/OpenACC/Transforms/ACCMapInfoPrep.cpp
@@ -195,7 +195,44 @@ static Value loadRecordTypeSizeFromTypeDesc(
   return fir::LoadOp::create(builder, loc, addr);
 }
 
-static Value materializeMapSize(acc::OpenACCSupport &support,
+/// Materialize the storage size of \p type. FIR's layout utility handles the
+/// recursively statically-sized case. Recurse through a sequence when its
+/// element instead needs a runtime size, and obtain that leaf size from a
+/// derived type's type descriptor.
+static Value materializeTypeSizeBytes(acc::OpenACCSupport &support,
+                                      ModuleOp module, Location loc, Type type,
+                                      Operation *entryOp,
+                                      std::optional<SymbolTable> &symbolTable,
+                                      OpBuilder &builder) {
+  type = fir::unwrapRefType(type);
+  if (std::optional<int64_t> staticSize =
+          computeTypeSizeBytes(support, module, type))
+    return arith::ConstantIntOp::create(builder, loc, builder.getI64Type(),
+                                        *staticSize);
+
+  if (auto sequenceType = dyn_cast<fir::SequenceType>(type)) {
+    if (sequenceType.hasUnknownShape() || sequenceType.hasDynamicExtents())
+      return {};
+    Value elementSize =
+        materializeTypeSizeBytes(support, module, loc, sequenceType.getEleTy(),
+                                 entryOp, symbolTable, builder);
+    if (!elementSize)
+      return {};
+    int64_t elementCount = sequenceType.getConstantArraySize();
+    if (elementCount == 1)
+      return elementSize;
+    Value count = arith::ConstantIntOp::create(
+        builder, loc, elementSize.getType(), elementCount);
+    return arith::MulIOp::create(builder, loc, elementSize, count);
+  }
+
+  if (auto recordType = dyn_cast<fir::RecordType>(type))
+    return loadRecordTypeSizeFromTypeDesc(loc, recordType, entryOp, symbolTable,
+                                          builder);
+  return {};
+}
+
+static Value materializeMapSize(acc::OpenACCSupport &support, ModuleOp module,
                                 Operation *entryOp, Value var, Type varType,
                                 acc::DataDescKind descKind, ValueRange bounds,
                                 acc::MapFlags mapFlags,
@@ -219,14 +256,10 @@ static Value materializeMapSize(acc::OpenACCSupport &support,
 
   // Derived types with descriptor fields often have no compile-time layout
   // size; load the type descriptor's size-in-bytes field instead.
-  if (staticSize < 0) {
-    if (auto recordType =
-            dyn_cast<fir::RecordType>(fir::unwrapRefType(varType))) {
-      if (Value dynamicSize = loadRecordTypeSizeFromTypeDesc(
-              loc, recordType, entryOp, symbolTable, builder))
-        return dynamicSize;
-    }
-  }
+  if (staticSize < 0)
+    if (Value dynamicSize = materializeTypeSizeBytes(
+            support, module, loc, varType, entryOp, symbolTable, builder))
+      return dynamicSize;
 
   // An implicit present of an object whose size is not recoverable is only an
   // address lookup. Size 0 matches the present-table entry whatever its
@@ -298,29 +331,11 @@ static Value materializePrivateStorageSize(
     staticTy = fir::SequenceType::get(staticExtents, elementType);
   }
 
-  Value size;
-  if (std::optional<int64_t> staticBytes =
-          computeTypeSizeBytes(support, module, staticTy)) {
-    size = arith::ConstantIntOp::create(builder, loc, builder.getI64Type(),
-                                        *staticBytes);
-  } else if (auto recordType = dyn_cast<fir::RecordType>(elementType)) {
-    // A derived type whose layout is not computable here carries its padded
-    // size in the Fortran type descriptor.
-    size = loadRecordTypeSizeFromTypeDesc(
-        loc, recordType, privatizeOp.getOperation(), symbolTable, builder);
-    if (!size)
-      return {};
-    int64_t staticExtent = 1;
-    for (int64_t extent : staticExtents)
-      staticExtent *= extent;
-    if (staticExtent != 1) {
-      Value extentVal = arith::ConstantIntOp::create(
-          builder, loc, size.getType(), staticExtent);
-      size = arith::MulIOp::create(builder, loc, size, extentVal);
-    }
-  } else {
+  Value size = materializeTypeSizeBytes(support, module, loc, staticTy,
+                                        privatizeOp.getOperation(), symbolTable,
+                                        builder);
+  if (!size)
     return {};
-  }
 
   for (Value dynamicSize : dynamicSizes) {
     Value extentVal =
@@ -418,8 +433,9 @@ buildMapInfo(acc::OpenACCSupport &support, ModuleOp module, Operation *entryOp,
     acc::populateSourceExtents(bounds, seqTy.getShape(), builder);
 
   Location loc = entryOp->getLoc();
-  Value size = materializeMapSize(support, entryOp, var, varType, descKind,
-                                  bounds, mapFlags, symbolTable, builder);
+  Value size = materializeMapSize(support, module, entryOp, var, varType,
+                                  descKind, bounds, mapFlags, symbolTable,
+                                  builder);
 
   return acc::MapInfoOp::create(builder, loc, entryOp->getResult(0).getType(),
                                 var, varType, mapFlags, attachPoint, desc,
diff --git a/flang/test/Fir/OpenACC/acc-fir-map-info-prep-privatize.mlir b/flang/test/Fir/OpenACC/acc-fir-map-info-prep-privatize.mlir
index 54953870331f0..4f5d9dd2b44cd 100644
--- a/flang/test/Fir/OpenACC/acc-fir-map-info-prep-privatize.mlir
+++ b/flang/test/Fir/OpenACC/acc-fir-map-info-prep-privatize.mlir
@@ -69,6 +69,34 @@ func.func @private_static_record() {
 
 // -----
 
+// A record with descriptor fields gets its padded element size from the
+// Fortran type descriptor before the static array extent is applied.
+
+// CHECK-LABEL: func.func @private_static_descriptor_record
+// CHECK: %[[PRIV:.*]] = acc.privatize
+// CHECK: fir.type_desc !fir.type<_QMtypesTdescriptor_pair{{.*}}>
+// CHECK: %[[TDESC:.*]] = fir.address_of(@_QMtypesEXdtXdescriptor_pair)
+// CHECK: fir.field_index sizeinbytes
+// CHECK: %[[ELEMENT_SIZE:.*]] = fir.load
+// CHECK: %[[COUNT:.*]] = arith.constant 6 : i64
+// CHECK: %[[SIZE:.*]] = arith.muli %[[ELEMENT_SIZE]], %[[COUNT]] : i64
+// CHECK: acc.map_info varPtr(%[[PRIV]]
+// CHECK-SAME: size(%[[SIZE]] : i64)
+// CHECK-SAME: mapFlags(private)
+
+fir.global linkonce_odr @_QMtypesEXdtXdescriptor_pair constant target : !fir.type<_QM__fortran_type_infoTderivedtype{sizeinbytes:i64}> {
+  %0 = fir.undefined !fir.type<_QM__fortran_type_infoTderivedtype{sizeinbytes:i64}>
+  fir.has_value %0 : !fir.type<_QM__fortran_type_infoTderivedtype{sizeinbytes:i64}>
+}
+
+func.func @private_static_descriptor_record() {
+  %priv = acc.privatize par_dims(#acc<par_dims[]>)
+      : () -> !acc.private_type<!fir.array<6x!fir.type<_QMtypesTdescriptor_pair{p:!fir.box<!fir.ptr<!fir.array<?xf64>>>,x:!fir.box<!fir.ptr<!fir.array<?x?xf64>>>}>>>
+  return
+}
+
+// -----
+
 // A runtime extent is multiplied in, so the size is an SSA value rather than a
 // constant. This is the case that has no memref equivalent: memref cannot hold
 // a record element type.
diff --git a/flang/test/Fir/OpenACC/acc-fir-map-info-prep.mlir b/flang/test/Fir/OpenACC/acc-fir-map-info-prep.mlir
index 06246ff4342b9..3b866feaebd7c 100644
--- a/flang/test/Fir/OpenACC/acc-fir-map-info-prep.mlir
+++ b/flang/test/Fir/OpenACC/acc-fir-map-info-prep.mlir
@@ -56,6 +56,36 @@ func.func @derived_with_box() {
   return
 }
 
+// An array of derived types whose layout is only available from its type
+// descriptor uses the padded element size times the static element count.
+//
+// CHECK-LABEL: func.func @array_of_derived_with_boxes
+// CHECK: fir.type_desc !fir.type<_QMtypesTdescriptor_pair{{.*}}>
+// CHECK: %[[TDESC:.*]] = fir.address_of(@_QMtypesEXdtXdescriptor_pair)
+// CHECK: fir.field_index sizeinbytes
+// CHECK: %[[ELEMENT_SIZE:.*]] = fir.load
+// CHECK: %[[COUNT:.*]] = arith.constant 6 : i64
+// CHECK: %[[SIZE:.*]] = arith.muli %[[ELEMENT_SIZE]], %[[COUNT]] : i64
+// CHECK: acc.map_info
+// CHECK-SAME: size(%[[SIZE]] : i64)
+// CHECK-SAME: mapFlags(to)
+
+fir.global linkonce_odr @_QMtypesEXdtXdescriptor_pair constant target : !fir.type<_QM__fortran_type_infoTderivedtype{sizeinbytes:i64}> {
+  %0 = fir.undefined !fir.type<_QM__fortran_type_infoTderivedtype{sizeinbytes:i64}>
+  fir.has_value %0 : !fir.type<_QM__fortran_type_infoTderivedtype{sizeinbytes:i64}>
+}
+
+func.func @array_of_derived_with_boxes() {
+  %array = fir.undefined !fir.ref<!fir.array<6x!fir.type<_QMtypesTdescriptor_pair{p:!fir.box<!fir.ptr<!fir.array<?xf64>>>,x:!fir.box<!fir.ptr<!fir.array<?x?xf64>>>}>>>
+  %copy = acc.copyin varPtr(%array : !fir.ref<!fir.array<6x!fir.type<_QMtypesTdescriptor_pair{p:!fir.box<!fir.ptr<!fir.array<?xf64>>>,x:!fir.box<!fir.ptr<!fir.array<?x?xf64>>>}>>>)
+      dataClause(acc_copyin) name("array")
+      -> !fir.ref<!fir.array<6x!fir.type<_QMtypesTdescriptor_pair{p:!fir.box<!fir.ptr<!fir.array<?xf64>>>,x:!fir.box<!fir.ptr<!fir.array<?x?xf64>>>}>>>
+  acc.data dataOperands(%copy : !fir.ref<!fir.array<6x!fir.type<_QMtypesTdescriptor_pair{p:!fir.box<!fir.ptr<!fir.array<?xf64>>>,x:!fir.box<!fir.ptr<!fir.array<?x?xf64>>>}>>>) {
+    acc.terminator
+  }
+  return
+}
+
 // firstprivate_map is a live-in (not on dataOperands) but still gets map_info.
 // A partial array section keeps the full-array byte size on map_info; bounds
 // carry the section.

>From 5f23450da3fff12743005b46df6e7b9ba2b52b54 Mon Sep 17 00:00:00 2001
From: Razvan Lupusoru <rlupusoru at nvidia.com>
Date: Wed, 9 Sep 2026 10:48:13 -0700
Subject: [PATCH 2/2] Fix formatting

---
 flang/lib/Optimizer/OpenACC/Transforms/ACCMapInfoPrep.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/flang/lib/Optimizer/OpenACC/Transforms/ACCMapInfoPrep.cpp b/flang/lib/Optimizer/OpenACC/Transforms/ACCMapInfoPrep.cpp
index 9f32f9d6a9360..34dc67d688e26 100644
--- a/flang/lib/Optimizer/OpenACC/Transforms/ACCMapInfoPrep.cpp
+++ b/flang/lib/Optimizer/OpenACC/Transforms/ACCMapInfoPrep.cpp
@@ -433,9 +433,9 @@ buildMapInfo(acc::OpenACCSupport &support, ModuleOp module, Operation *entryOp,
     acc::populateSourceExtents(bounds, seqTy.getShape(), builder);
 
   Location loc = entryOp->getLoc();
-  Value size = materializeMapSize(support, module, entryOp, var, varType,
-                                  descKind, bounds, mapFlags, symbolTable,
-                                  builder);
+  Value size =
+      materializeMapSize(support, module, entryOp, var, varType, descKind,
+                         bounds, mapFlags, symbolTable, builder);
 
   return acc::MapInfoOp::create(builder, loc, entryOp->getResult(0).getType(),
                                 var, varType, mapFlags, attachPoint, desc,



More information about the flang-commits mailing list