[flang-commits] [flang] [mlir] [acc] Pre-cg pass for handling flang data mapping to offload runtime (PR #221282)
via flang-commits
flang-commits at lists.llvm.org
Fri Sep 4 09:53:09 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-mlir
Author: Razvan Lupusoru (razvanlupusoru)
<details>
<summary>Changes</summary>
Introduce acc.map_info as the acc dialect operation that captures a single mapped object's offload facts (attach point, descriptor kind, bounds, map flags, and size) so later codegen can lower data clauses to the offload runtime from one representation.
Add a Flang pre-codegen pass, ACCMapInfoPrep, that materializes acc.map_info for FIR-typed operands: it infers Fortran descriptor attach and CFI facts, sizes mapped and privatized storage, and folds paired enter/exit clause effects into map flags. This keeps FIR-specific mapping logic out of ACCToLLVM and leaves that conversion to consume map_info verbatim.
---
Patch is 147.29 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/221282.diff
29 Files Affected:
- (modified) flang/include/flang/Optimizer/OpenACC/Passes.td (+18)
- (modified) flang/include/flang/Semantics/runtime-type-info.h (+4)
- (modified) flang/lib/Optimizer/Dialect/FIRType.cpp (+3)
- (modified) flang/lib/Optimizer/OpenACC/Analysis/FIROpenACCSupportAnalysis.cpp (+2-1)
- (modified) flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp (+6)
- (added) flang/lib/Optimizer/OpenACC/Transforms/ACCMapInfoPrep.cpp (+562)
- (modified) flang/lib/Optimizer/OpenACC/Transforms/CMakeLists.txt (+3-1)
- (modified) flang/lib/Semantics/runtime-type-info.cpp (+2-2)
- (added) flang/test/Fir/OpenACC/acc-fir-map-info-prep-attach.mlir (+81)
- (added) flang/test/Fir/OpenACC/acc-fir-map-info-prep-clauses.mlir (+229)
- (added) flang/test/Fir/OpenACC/acc-fir-map-info-prep-declare-global.mlir (+40)
- (added) flang/test/Fir/OpenACC/acc-fir-map-info-prep-exit.mlir (+222)
- (added) flang/test/Fir/OpenACC/acc-fir-map-info-prep-implicit-present.mlir (+135)
- (added) flang/test/Fir/OpenACC/acc-fir-map-info-prep-privatize.mlir (+122)
- (added) flang/test/Fir/OpenACC/acc-fir-map-info-prep-types.mlir (+228)
- (added) flang/test/Fir/OpenACC/acc-fir-map-info-prep.mlir (+86)
- (modified) flang/unittests/Optimizer/OpenACC/FIROpenACCSupportAnalysisTest.cpp (+14)
- (added) mlir/include/mlir/Dialect/OpenACC/OpenACCCGEnums.td (+85)
- (modified) mlir/include/mlir/Dialect/OpenACC/OpenACCCGOps.td (+122)
- (modified) mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td (+22-3)
- (modified) mlir/include/mlir/Dialect/OpenACC/OpenACCUtilsCG.h (+57)
- (modified) mlir/include/mlir/Dialect/OpenACC/OpenACCUtilsType.h (+12-5)
- (modified) mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp (+78-46)
- (modified) mlir/lib/Dialect/OpenACC/IR/OpenACCCG.cpp (+33)
- (modified) mlir/lib/Dialect/OpenACC/Utils/OpenACCUtilsCG.cpp (+302)
- (modified) mlir/lib/Dialect/OpenACC/Utils/OpenACCUtilsType.cpp (+18-3)
- (added) mlir/test/Dialect/OpenACC/invalid-cg-mapinfo.mlir (+44)
- (added) mlir/test/Dialect/OpenACC/ops-cg-mapinfo.mlir (+143)
- (modified) mlir/test/Dialect/OpenACC/ops.mlir (+12)
``````````diff
diff --git a/flang/include/flang/Optimizer/OpenACC/Passes.td b/flang/include/flang/Optimizer/OpenACC/Passes.td
index a2c5e4677fcd2..0a1f636e1849c 100644
--- a/flang/include/flang/Optimizer/OpenACC/Passes.td
+++ b/flang/include/flang/Optimizer/OpenACC/Passes.td
@@ -109,6 +109,24 @@ def ACCOptimizeFirstprivateMap
let dependentDialects = ["mlir::acc::OpenACCDialect", "fir::FIROpsDialect"];
}
+def ACCMapInfoPrep
+ : InterfacePass<"acc-fir-map-info-prep", "mlir::FunctionOpInterface"> {
+ let summary = "Materialize acc.map_info for FIR mappings and privatization";
+ let description = [{
+ Replaces FIR-typed OpenACC data-entry operations, and the data-exit
+ operations paired with them, with `acc.map_info`. FIR-specific facts
+ include attach points inferred from Fortran descriptors (allocatable,
+ pointer, and class), CFI `descKind`, mapped sizes, and `mapFlags` that
+ fold enter and exit clause effects. Privatized storage is wrapped with its
+ byte size and private parallel-level flags, forming the contract for the
+ runtime allocation and replication of that storage. The result is a single
+ representation of runtime map and allocation metadata that no longer
+ depends on FIR types or attributes.
+ }];
+ let dependentDialects = ["mlir::acc::OpenACCDialect", "fir::FIROpsDialect",
+ "mlir::arith::ArithDialect"];
+}
+
def ACCDevicePtrToCUFKernel
: Pass<"acc-device-ptr-to-cuf-kernel", "mlir::ModuleOp"> {
let summary = "Pass device addresses to CUDA Fortran kernels launched inside "
diff --git a/flang/include/flang/Semantics/runtime-type-info.h b/flang/include/flang/Semantics/runtime-type-info.h
index 06a0807462b61..27e355f35a299 100644
--- a/flang/include/flang/Semantics/runtime-type-info.h
+++ b/flang/include/flang/Semantics/runtime-type-info.h
@@ -40,6 +40,10 @@ constexpr char typeInfoBuiltinModule[]{"__fortran_type_info"};
/// derived type descriptors.
constexpr char typeDescriptorTypeName[]{"derivedtype"};
+/// Name of the size-in-bytes component in the DerivedType type of the
+/// __Fortran_type_info module
+constexpr char sizeInBytesCompName[]{"sizeinbytes"};
+
/// Name of the bindings descriptor component in the DerivedType type of the
/// __Fortran_type_info module
constexpr char bindingDescCompName[]{"binding"};
diff --git a/flang/lib/Optimizer/Dialect/FIRType.cpp b/flang/lib/Optimizer/Dialect/FIRType.cpp
index 178860239e17d..5f0dd68aa9396 100644
--- a/flang/lib/Optimizer/Dialect/FIRType.cpp
+++ b/flang/lib/Optimizer/Dialect/FIRType.cpp
@@ -1650,6 +1650,9 @@ fir::getTypeSizeAndAlignment(mlir::Location loc, mlir::Type ty,
return std::pair{size, alignment};
}
if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(ty)) {
+ // Dynamic / unknown shapes have no compile-time byte size.
+ if (seqTy.hasDynamicExtents() || seqTy.hasUnknownShape())
+ return std::nullopt;
auto result = getTypeSizeAndAlignment(loc, seqTy.getEleTy(), dl, kindMap);
if (!result)
return result;
diff --git a/flang/lib/Optimizer/OpenACC/Analysis/FIROpenACCSupportAnalysis.cpp b/flang/lib/Optimizer/OpenACC/Analysis/FIROpenACCSupportAnalysis.cpp
index d8a0c43e40117..d0fe71657a6bf 100644
--- a/flang/lib/Optimizer/OpenACC/Analysis/FIROpenACCSupportAnalysis.cpp
+++ b/flang/lib/Optimizer/OpenACC/Analysis/FIROpenACCSupportAnalysis.cpp
@@ -63,7 +63,8 @@ FIROpenACCSupportAnalysis::getTypeSizeAndAlignment(
if (!dl)
return std::nullopt;
- if (isa<fir::ReferenceType, fir::HeapType, fir::LLVMPointerType>(ty))
+ if (isa<fir::ReferenceType, fir::PointerType, fir::HeapType,
+ fir::LLVMPointerType>(ty))
return mlir::acc::getTypeSizeAndAlignment(
LLVM::LLVMPointerType::get(ty.getContext()), module, *dl, &support);
diff --git a/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp b/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp
index 2a1230dc7f5c9..e070de2d908b2 100644
--- a/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp
+++ b/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp
@@ -27,6 +27,7 @@
#include "flang/Optimizer/Support/Utils.h"
#include "flang/Optimizer/Transforms/FIRToMemRefTypeConverter.h"
#include "mlir/Dialect/Arith/IR/Arith.h"
+#include "mlir/Dialect/LLVMIR/LLVMTypes.h"
#include "mlir/Dialect/OpenACC/OpenACC.h"
#include "mlir/Dialect/OpenACC/OpenACCUtils.h"
#include "mlir/IR/BuiltinOps.h"
@@ -100,6 +101,11 @@ std::optional<llvm::TypeSize> OpenACCMappableModel<Ty>::getSizeInBytes(
if (auto mappableTy = mlir::dyn_cast<mlir::acc::MappableType>(eleTy))
return mappableTy.getSizeInBytes(var, accBounds, dataLayout);
+ // Procedure pointers map as a single address-sized slot.
+ if (mlir::isa<mlir::FunctionType>(eleTy))
+ return llvm::TypeSize::getFixed(dataLayout.getTypeSize(
+ mlir::LLVM::LLVMPointerType::get(type.getContext())));
+
// Dynamic extents or unknown ranks generally do not have compile-time
// computable dimensions.
auto seqType = mlir::dyn_cast<fir::SequenceType>(eleTy);
diff --git a/flang/lib/Optimizer/OpenACC/Transforms/ACCMapInfoPrep.cpp b/flang/lib/Optimizer/OpenACC/Transforms/ACCMapInfoPrep.cpp
new file mode 100644
index 0000000000000..4ba5cc8b2d909
--- /dev/null
+++ b/flang/lib/Optimizer/OpenACC/Transforms/ACCMapInfoPrep.cpp
@@ -0,0 +1,562 @@
+//===- ACCMapInfoPrep.cpp - Materialize acc.map_info for FIR --------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass replaces the OpenACC data clause operations on FIR-typed operands
+// with acc.map_info. A map entry states everything the offload runtime needs
+// about one mapped object: the address to transfer, the pointer slot to attach
+// it to, the Fortran descriptor that describes it, the element and object
+// sizes, the bounds of the section being mapped, and the map-type flags. All
+// of that is derived from FIR types and attributes here, so that lowering to
+// runtime calls can work from the map entry alone.
+//
+// A data entry operation and the data exit operations paired with it describe
+// the same object, so they collapse into a single map entry whose flags carry
+// the effects of both directions. Privatized storage (acc.privatize,
+// acc.firstprivate_map) is wrapped the same way, with the parallel levels that
+// govern its replication.
+//
+// Example transformation, for an allocatable scalar in a copy clause:
+//
+// Before:
+// %slot = fir.declare %alloca : !fir.ref<!fir.box<!fir.heap<i32>>>
+// %in = acc.copyin varPtr(%slot : !fir.ref<!fir.box<!fir.heap<i32>>>)
+// dataClause(acc_copy) name("n") -> !fir.ref<!fir.box<!fir.heap<i32>>>
+// acc.data dataOperands(%in : !fir.ref<!fir.box<!fir.heap<i32>>>) {
+// ...
+// }
+// acc.copyout accPtr(%in : !fir.ref<!fir.box<!fir.heap<i32>>>)
+// to varPtr(%slot : !fir.ref<!fir.box<!fir.heap<i32>>>)
+// dataClause(acc_copy) name("n")
+//
+// After:
+// %slot = fir.declare %alloca : !fir.ref<!fir.box<!fir.heap<i32>>>
+// %c0 = arith.constant 0 : i64
+// // The copyin and the copyout fold into one entry, so the flags name both
+// // directions. The descriptor makes this an attach (ptr_and_obj) of a
+// // CFI-described object, and a size of zero defers the byte count to that
+// // descriptor. exitLoc points at the erased copyout.
+// %map = acc.map_info varPtr(%slot : !fir.ref<!fir.box<!fir.heap<i32>>>)
+// size(%c0 : i64) elementSize(4) name("n") exitLoc(...)
+// descKind(cfi) mapFlags(to,from,ptr_and_obj)
+// -> !fir.ref<!fir.box<!fir.heap<i32>>>
+// acc.data dataOperands(%map : !fir.ref<!fir.box<!fir.heap<i32>>>) {
+// ...
+// }
+//
+//===----------------------------------------------------------------------===//
+
+#include "flang/Optimizer/Dialect/CUF/Attributes/CUFAttr.h"
+#include "flang/Optimizer/Dialect/FIROps.h"
+#include "flang/Optimizer/Dialect/FIRType.h"
+#include "flang/Optimizer/OpenACC/Analysis/FIROpenACCSupportAnalysis.h"
+#include "flang/Optimizer/OpenACC/Passes.h"
+#include "flang/Optimizer/OpenACC/Support/FIROpenACCUtils.h"
+#include "flang/Optimizer/Support/InternalNames.h"
+#include "flang/Semantics/runtime-type-info.h"
+#include "mlir/Dialect/Arith/IR/Arith.h"
+#include "mlir/Dialect/OpenACC/Analysis/OpenACCSupport.h"
+#include "mlir/Dialect/OpenACC/OpenACC.h"
+#include "mlir/Dialect/OpenACC/OpenACCUtilsCG.h"
+#include "mlir/Dialect/OpenACC/OpenACCUtilsType.h"
+#include "mlir/IR/BuiltinOps.h"
+#include "mlir/IR/SymbolTable.h"
+#include "mlir/Pass/Pass.h"
+
+namespace fir {
+namespace acc {
+#define GEN_PASS_DEF_ACCMAPINFOPREP
+#include "flang/Optimizer/OpenACC/Passes.h.inc"
+} // namespace acc
+} // namespace fir
+
+using namespace mlir;
+
+namespace {
+
+/// Returns the pointer slot holding the address of \p mapVar, which the runtime
+/// rewrites once the pointee has a device copy. Such a slot exists only when
+/// the clause maps a pointee obtained by dereferencing it; mapping the slot
+/// itself has no second indirection and therefore no attach point. Only slots
+/// reached through a Fortran descriptor are recognized here.
+static Value findAttachPoint(Value mapVar) {
+ if (auto boxAddr = mapVar.getDefiningOp<fir::BoxAddrOp>()) {
+ if (auto load = boxAddr.getVal().getDefiningOp<fir::LoadOp>())
+ return load.getMemref();
+ }
+ if (fir::isa_box_type(fir::unwrapRefType(mapVar.getType()))) {
+ if (auto load = mapVar.getDefiningOp<fir::LoadOp>())
+ return load.getMemref();
+ }
+ return {};
+}
+
+/// True when the clause maps descriptor storage rather than a plain object. The
+/// runtime must then treat the entry as pointer-and-object: besides the
+/// descriptor bytes it fixes up the base address recorded inside them.
+///
+/// The base-address slot is identified downstream by the descriptor address
+/// (`desc`) alone, which currently works only because `base_addr` sits at
+/// offset 0 of the F18/CFI descriptor, so `&desc == &desc->base_addr`. If that
+/// layout changes, the attach point must be formed from the descriptor's actual
+/// `base_addr` field rather than the descriptor address.
+static bool mapsDescriptorStorage(Value mapVar) {
+ auto refTy = dyn_cast<fir::ReferenceType>(mapVar.getType());
+ return refTy && fir::isa_box_type(refTy.getEleTy());
+}
+
+static bool isManagedData(Value var) {
+ auto hasManagedAttr = [](Value v) {
+ Operation *op = v.getDefiningOp();
+ return op && cuf::hasDataAttr(op, cuf::DataAttribute::Managed);
+ };
+ if (hasManagedAttr(var))
+ return true;
+ Value orig = fir::acc::getOriginalDef(var, /*stripDeclare=*/false);
+ return orig && orig != var && hasManagedAttr(orig);
+}
+
+static std::pair<acc::DataDescKind, Value>
+findDescriptorFacts(Value mapVar, Type mappedObjectType, bool isImplicit) {
+ Type mapTy = mapVar.getType();
+ if (auto refTy = dyn_cast<fir::ReferenceType>(mapTy)) {
+ if (fir::isa_box_type(refTy.getEleTy()))
+ return {acc::DataDescKind::cfi, mapVar};
+ }
+ if (fir::isa_box_type(fir::unwrapRefType(mapTy)))
+ return {acc::DataDescKind::cfi, mapVar};
+ // box_addr of a loaded box can be either the pointee of a nested descriptor
+ // map or a host data-base address derived from an already-mapped box. The
+ // latter is always an implicit clause; only treat the explicit case as CFI.
+ if (!isImplicit) {
+ if (auto boxAddr = mapVar.getDefiningOp<fir::BoxAddrOp>()) {
+ Value boxVal = boxAddr.getVal();
+ if (fir::isa_box_type(boxVal.getType()) &&
+ boxVal.getDefiningOp<fir::LoadOp>())
+ return {acc::DataDescKind::cfi, boxVal};
+ }
+ }
+ (void)mappedObjectType;
+ return {acc::DataDescKind::none, {}};
+}
+
+/// Byte size of \p type as storage - what the type alone describes, without a
+/// value to interpret it as a mapped object. The types here are mostly FIR
+/// ones, which only the OpenACCSupport implementation sizes; it falls back to
+/// the dialect-agnostic acc::getTypeSizeAndAlignment for the rest.
+static std::optional<int64_t> computeTypeSizeBytes(acc::OpenACCSupport &support,
+ ModuleOp module, Type type) {
+ std::optional<acc::TypeSizeAndAlignment> sizeAndAlignment =
+ support.getTypeSizeAndAlignment(type, module);
+ if (!sizeAndAlignment || sizeAndAlignment->first.isScalable())
+ return std::nullopt;
+ return static_cast<int64_t>(sizeAndAlignment->first.getFixedValue());
+}
+
+/// Load the size-in-bytes field from the Fortran type descriptor for
+/// \p recordType. Returns null when no matching type-descriptor global is
+/// present.
+static Value loadRecordTypeSizeFromTypeDesc(
+ Location loc, fir::RecordType recordType, Operation *entryOp,
+ std::optional<SymbolTable> &symbolTable, OpBuilder &builder) {
+ ModuleOp module = entryOp->getParentOfType<ModuleOp>();
+ if (!module)
+ return {};
+
+ // Keep a TypeDesc use so later passes see the record as referenced.
+ (void)fir::TypeDescOp::create(builder, loc, TypeAttr::get(recordType));
+
+ if (!symbolTable)
+ symbolTable.emplace(module);
+ StringAttr typeDescName = builder.getStringAttr(
+ fir::NameUniquer::getTypeDescriptorAssemblyName(recordType.getName()));
+ auto global = symbolTable->lookup<fir::GlobalOp>(typeDescName);
+ if (!global)
+ return {};
+
+ auto typeDescRecTy = dyn_cast<fir::RecordType>(global.getType());
+ if (!typeDescRecTy)
+ return {};
+
+ Value typeDescAddr = fir::AddrOfOp::create(
+ builder, loc, fir::ReferenceType::get(typeDescRecTy), global.getSymbol());
+ Type fieldTy = fir::FieldType::get(builder.getContext());
+ Value field = fir::FieldIndexOp::create(
+ builder, loc, fieldTy, Fortran::semantics::sizeInBytesCompName,
+ typeDescRecTy, ValueRange{});
+ Type coorTy = fir::ReferenceType::get(
+ typeDescRecTy.getType(Fortran::semantics::sizeInBytesCompName));
+ Value addr =
+ fir::CoordinateOp::create(builder, loc, coorTy, typeDescAddr, field);
+ return fir::LoadOp::create(builder, loc, addr);
+}
+
+static Value materializeMapSize(acc::OpenACCSupport &support,
+ Operation *entryOp, Value var, Type varType,
+ acc::DataDescKind descKind, ValueRange bounds,
+ acc::MapFlags mapFlags,
+ std::optional<SymbolTable> &symbolTable,
+ OpBuilder &builder) {
+ Location loc = entryOp->getLoc();
+ Type i64Ty = builder.getI64Type();
+
+ int64_t staticSize = -1;
+ if (std::optional<DataLayout> dl = acc::getDataLayout(entryOp)) {
+ // Privatized maps keep the full object ArgSize; AccDataDesc carries the
+ // section. Device firstprivate copies still index with the parent lower
+ // bound, so a compact section size (or ArgSize 0) is incorrect.
+ if (bitEnumContainsAny(mapFlags, acc::MapFlags::private_))
+ staticSize = acc::computeMapInfoSizeBytes(
+ var, varType, acc::DataDescKind::none, /*bounds=*/{}, *dl, &support);
+ else
+ staticSize = acc::computeMapInfoSizeBytes(var, varType, descKind, bounds,
+ *dl, &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;
+ }
+ }
+
+ // 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
+ // extents are, including a zero-sized array, whereas an unknown size does
+ // not. An explicit clause keeps the unknown size so that the runtime can
+ // report the missing data instead.
+ if (staticSize < 0 && bounds.empty() &&
+ bitEnumContainsAll(mapFlags,
+ acc::MapFlags::present | acc::MapFlags::implicit))
+ staticSize = 0;
+
+ return arith::ConstantIntOp::create(builder, loc, i64Ty, staticSize);
+}
+
+/// Describes the storage of \p baseTy - the base type of `acc.private_type` -
+/// as an element type whose extents are appended to \p extents. Extents that
+/// the type does not encode are `ShapedType::kDynamic` and are supplied by the
+/// `acc.privatize` dynamic sizes. Returns a null type when the type does not
+/// describe the storage, such as a descriptor that carries its own extents.
+static Type getPrivateStorageShape(Type baseTy,
+ SmallVectorImpl<int64_t> &extents) {
+ if (auto memrefTy = dyn_cast<MemRefType>(baseTy)) {
+ llvm::append_range(extents, memrefTy.getShape());
+ return memrefTy.getElementType();
+ }
+
+ Type storageTy = baseTy;
+ if (Type eleTy = fir::dyn_cast_ptrOrBoxEleTy(baseTy))
+ storageTy = eleTy;
+ if (fir::isa_box_type(storageTy))
+ return {};
+
+ if (auto seqTy = dyn_cast<fir::SequenceType>(storageTy)) {
+ if (seqTy.hasUnknownShape())
+ return {};
+ llvm::append_range(extents, seqTy.getShape());
+ return seqTy.getEleTy();
+ }
+ return storageTy;
+}
+
+/// Materializes the byte size of privatized storage. The extents that the type
+/// encodes are sized as an array, which is what applies the padded element
+/// stride; the dynamic extents are then multiplied in. Returns null when the
+/// size is not obtainable.
+static Value materializePrivateStorageSize(
+ acc::OpenACCSupport &support, ModuleOp module, acc::PrivatizeOp privatizeOp,
+ Type elementType, ArrayRef<int64_t> extents,
+ std::optional<SymbolTable> &symbolTable, OpBuilder &builder) {
+ Location loc = privatizeOp.getLoc();
+ ValueRange dynamicSizes = privatizeOp.getDynamicSizes();
+
+ SmallVector<int64_t> staticExtents;
+ for (int64_t extent : extents)
+ if (!ShapedType::isDynamic(extent))
+ staticExtents.push_back(extent);
+ if (extents.size() - staticExtents.size() != dynamicSizes.size())
+ return {};
+
+ // Size the extents the type encodes as a FIR array, which is what applies
+ // the padded element stride - also for a memref base, since the stride rule
+ // does not depend on where the element type comes from. A single element
+ // stands in when all extents are dynamic: its size is the stride that those
+ // extents multiply.
+ Type staticTy = elementType;
+ if (!extents.empty()) {
+ if (staticExtents.empty())
+ staticExtents.push_back(1);
+ 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 {
+ return {};
+ }
+
+ for (Value dynamicSize : dynamicSizes) {
+ Value extentVal =
+ arith::IndexCastOp::create(builder, loc, size.getType(), dynamicSize);
+ size = arith::MulIOp::create(builder, loc, size, extentVal);
+ }
+ return size;
+}
+
+/// Wraps \p privatizeOp so that privatized storage carries offload facts in
+/// `acc.map_info` like any other mapped variable, including the parallel
+/// levels that select gang/worker/vector private replication.
+static std::optional<acc::MapInfoOp> buildPriv...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/221282
More information about the flang-commits
mailing list