[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