[flang-commits] [flang] [mlir] [mlir][acc][flang] Add type sizing utilities (PR #208074)

Razvan Lupusoru via flang-commits flang-commits at lists.llvm.org
Tue Jul 7 12:49:28 PDT 2026


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

>From 537a535502bab6d9b3dd079a4e93a17927344e06 Mon Sep 17 00:00:00 2001
From: Razvan Lupusoru <rlupusoru at nvidia.com>
Date: Tue, 7 Jul 2026 12:06:23 -0700
Subject: [PATCH 1/3] [mlir][acc][flang] Add type sizing utilities

Add a general acc utility for computing the size and alignment
of a type. It works for simple scalar types as well as nested and
aggregate types like arrays, tuples, and structures.

Because some types come from other dialects, the utility can hand
those off to a specialized helper that understands them. This lets
sizing work seamlessly even for mixed types, such as an aggregate
whose members come from a different dialect.

Add a Fortran-specific helper so Fortran types are sized correctly,
falling back to the general utility for everything else.

Include unit tests covering a range of scenarios, including scalars,
arrays, aggregates, and mixed-dialect types.
---
 .../Analysis/FIROpenACCSupportAnalysis.h      |   5 +
 .../Optimizer/OpenACC/Analysis/CMakeLists.txt |   1 +
 .../Analysis/FIROpenACCSupportAnalysis.cpp    |  40 +++++
 flang/unittests/Optimizer/CMakeLists.txt      |   4 +
 .../OpenACC/FIROpenACCSupportAnalysisTest.cpp | 149 ++++++++++++++++++
 .../Dialect/OpenACC/Analysis/OpenACCSupport.h |  37 +++++
 .../mlir/Dialect/OpenACC/OpenACCUtilsType.h   |  56 +++++++
 .../OpenACC/Analysis/OpenACCSupport.cpp       |   1 +
 mlir/lib/Dialect/OpenACC/Utils/CMakeLists.txt |   1 +
 .../OpenACC/Utils/OpenACCUtilsType.cpp        |  94 +++++++++++
 mlir/unittests/Dialect/OpenACC/CMakeLists.txt |   1 +
 .../Dialect/OpenACC/OpenACCUtilsTypeTest.cpp  |  83 ++++++++++
 12 files changed, 472 insertions(+)
 create mode 100644 flang/unittests/Optimizer/OpenACC/FIROpenACCSupportAnalysisTest.cpp
 create mode 100644 mlir/include/mlir/Dialect/OpenACC/OpenACCUtilsType.h
 create mode 100644 mlir/lib/Dialect/OpenACC/Utils/OpenACCUtilsType.cpp
 create mode 100644 mlir/unittests/Dialect/OpenACC/OpenACCUtilsTypeTest.cpp

diff --git a/flang/include/flang/Optimizer/OpenACC/Analysis/FIROpenACCSupportAnalysis.h b/flang/include/flang/Optimizer/OpenACC/Analysis/FIROpenACCSupportAnalysis.h
index c2aaaee13419c..8d2a90d3520d1 100644
--- a/flang/include/flang/Optimizer/OpenACC/Analysis/FIROpenACCSupportAnalysis.h
+++ b/flang/include/flang/Optimizer/OpenACC/Analysis/FIROpenACCSupportAnalysis.h
@@ -13,6 +13,7 @@
 #ifndef FORTRAN_OPTIMIZER_OPENACC_ANALYSIS_FIROPENACCSUPPORTANALYSIS_H
 #define FORTRAN_OPTIMIZER_OPENACC_ANALYSIS_FIROPENACCSUPPORTANALYSIS_H
 
+#include "mlir/Dialect/OpenACC/Analysis/OpenACCSupport.h"
 #include "mlir/Dialect/OpenACC/OpenACC.h"
 #include "mlir/IR/Operation.h"
 #include "mlir/IR/Region.h"
@@ -50,6 +51,10 @@ class FIROpenACCSupportAnalysis {
                         mlir::Operation **definingOpPtr);
 
   bool isValidValueUse(mlir::Value v, mlir::Region &region);
+
+  std::optional<mlir::acc::TypeSizeAndAlignment>
+  getTypeSizeAndAlignment(mlir::Type ty, mlir::ModuleOp module,
+                            mlir::acc::OpenACCSupport &support);
 };
 
 } // namespace acc
diff --git a/flang/lib/Optimizer/OpenACC/Analysis/CMakeLists.txt b/flang/lib/Optimizer/OpenACC/Analysis/CMakeLists.txt
index 22ed8ea246117..0eb387d58d1b9 100644
--- a/flang/lib/Optimizer/OpenACC/Analysis/CMakeLists.txt
+++ b/flang/lib/Optimizer/OpenACC/Analysis/CMakeLists.txt
@@ -13,6 +13,7 @@ add_flang_library(FIROpenACCAnalysis
   CUFAttrs
   CUFDialect
   FIRAnalysis
+  FIRCodeGen
   FIRDialect
   FIROpenACCSupport
   HLFIRDialect
diff --git a/flang/lib/Optimizer/OpenACC/Analysis/FIROpenACCSupportAnalysis.cpp b/flang/lib/Optimizer/OpenACC/Analysis/FIROpenACCSupportAnalysis.cpp
index cf4c38453c8ee..df6202563a461 100644
--- a/flang/lib/Optimizer/OpenACC/Analysis/FIROpenACCSupportAnalysis.cpp
+++ b/flang/lib/Optimizer/OpenACC/Analysis/FIROpenACCSupportAnalysis.cpp
@@ -13,10 +13,16 @@
 #include "flang/Optimizer/OpenACC/Analysis/FIROpenACCSupportAnalysis.h"
 
 #include "flang/Optimizer/Builder/Todo.h"
+#include "flang/Optimizer/CodeGen/TypeConverter.h"
 #include "flang/Optimizer/Dialect/CUF/Attributes/CUFAttr.h"
 #include "flang/Optimizer/Dialect/FIRType.h"
 #include "flang/Optimizer/OpenACC/Support/FIROpenACCUtils.h"
+#include "mlir/Dialect/LLVMIR/LLVMTypes.h"
+#include "mlir/Dialect/OpenACC/Analysis/OpenACCSupport.h"
 #include "mlir/Dialect/OpenACC/OpenACCUtils.h"
+#include "mlir/Dialect/OpenACC/OpenACCUtilsCG.h"
+#include "mlir/Dialect/OpenACC/OpenACCUtilsType.h"
+#include "mlir/IR/BuiltinOps.h"
 
 using namespace mlir;
 
@@ -86,5 +92,39 @@ bool FIROpenACCSupportAnalysis::isValidValueUse(Value v, Region &region) {
   return false;
 }
 
+std::optional<mlir::acc::TypeSizeAndAlignment>
+FIROpenACCSupportAnalysis::getTypeSizeAndAlignment(
+    Type ty, ModuleOp module, mlir::acc::OpenACCSupport &support) {
+  std::optional<DataLayout> dl = mlir::acc::getDataLayout(module);
+  if (!dl)
+    return std::nullopt;
+
+  if (isa<fir::ReferenceType, fir::HeapType, fir::LLVMPointerType>(ty)) {
+    return mlir::acc::getTypeSizeAndAlignment(
+        LLVM::LLVMPointerType::get(ty.getContext()), module, *dl, &support);
+  }
+
+  if (!fir::isa_fir_type(ty))
+    return mlir::acc::getTypeSizeAndAlignment(ty, module, *dl, &support);
+
+  fir::LLVMTypeConverter typeConverter(module, /*applyTBAA=*/false,
+                                       /*forceUnifiedTBAATree=*/false, *dl);
+  fir::KindMapping kindMap = typeConverter.getKindMap();
+
+  if (auto boxTy = dyn_cast<fir::BaseBoxType>(ty)) {
+    return mlir::acc::getTypeSizeAndAlignment(
+        typeConverter.convertBoxTypeAsStruct(boxTy), module, *dl, &support);
+  }
+
+  auto sizeAndAlignment = fir::getTypeSizeAndAlignment(
+      UnknownLoc::get(ty.getContext()), ty, *dl, kindMap);
+  if (!sizeAndAlignment)
+    return std::nullopt;
+
+  return mlir::acc::TypeSizeAndAlignment{
+      llvm::TypeSize::getFixed(sizeAndAlignment->first),
+      llvm::TypeSize::getFixed(sizeAndAlignment->second)};
+}
+
 } // namespace acc
 } // namespace fir
diff --git a/flang/unittests/Optimizer/CMakeLists.txt b/flang/unittests/Optimizer/CMakeLists.txt
index 3af6f9d2a3724..1697b64f12ed9 100644
--- a/flang/unittests/Optimizer/CMakeLists.txt
+++ b/flang/unittests/Optimizer/CMakeLists.txt
@@ -9,9 +9,11 @@ set(LIBS
   CUFDialect
   FIRBuilder
   FIRAnalysis
+  FIRCodeGen
   FIRCodeGenDialect
   FIRDialect
   FIRDialectSupport
+  FIROpenACCAnalysis
   FIROpenACCSupport
   FIRSupport
   FIRTransforms
@@ -37,6 +39,7 @@ add_flang_unittest(FlangOptimizerTests
   Builder/Runtime/StopTest.cpp
   Builder/Runtime/TransformationalTest.cpp
   OpenACC/FIROpenACCPointerLikeTypeInterfaceTest.cpp
+  OpenACC/FIROpenACCSupportAnalysisTest.cpp
   FIRCallInterfaceTest.cpp
   FIRContextTest.cpp
   FIRTypesTest.cpp
@@ -64,4 +67,5 @@ mlir_target_link_libraries(FlangOptimizerTests
   ${dialect_libs}
   ${extension_libs}
   MLIROpenACCDialect
+  MLIROpenACCUtils
   )
diff --git a/flang/unittests/Optimizer/OpenACC/FIROpenACCSupportAnalysisTest.cpp b/flang/unittests/Optimizer/OpenACC/FIROpenACCSupportAnalysisTest.cpp
new file mode 100644
index 0000000000000..89454a48ede34
--- /dev/null
+++ b/flang/unittests/Optimizer/OpenACC/FIROpenACCSupportAnalysisTest.cpp
@@ -0,0 +1,149 @@
+//===- FIROpenACCSupportAnalysisTest.cpp --------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "flang/Optimizer/OpenACC/Analysis/FIROpenACCSupportAnalysis.h"
+#include "gtest/gtest.h"
+#include "mlir/Dialect/DLTI/DLTI.h"
+#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
+#include "mlir/Dialect/LLVMIR/LLVMTypes.h"
+#include "mlir/Dialect/OpenACC/OpenACCUtilsCG.h"
+#include "mlir/Dialect/OpenACC/OpenACCUtilsType.h"
+#include "mlir/IR/BuiltinOps.h"
+#include "mlir/IR/BuiltinTypes.h"
+#include "mlir/Interfaces/DataLayoutInterfaces.h"
+#include "flang/Optimizer/CodeGen/TypeConverter.h"
+#include "flang/Optimizer/Dialect/FIRDialect.h"
+#include "flang/Optimizer/Dialect/FIRType.h"
+#include "flang/Optimizer/Dialect/Support/FIRContext.h"
+#include "flang/Optimizer/Dialect/Support/KindMapping.h"
+
+using namespace mlir;
+
+namespace {
+
+struct FIROpenACCSupportAnalysisTest : public testing::Test {
+  void SetUp() override {
+    context.loadDialect<fir::FIROpsDialect, DLTIDialect, LLVM::LLVMDialect>();
+    kindMap = std::make_unique<fir::KindMapping>(&context);
+    module = ModuleOp::create(UnknownLoc::get(&context));
+    fir::setKindMapping(module, *kindMap);
+    support.setImplementation(fir::acc::FIROpenACCSupportAnalysis());
+  }
+
+  std::optional<acc::TypeSizeAndAlignment> getExpectedFIRSize(Type ty) {
+    std::optional<DataLayout> dl = acc::getDataLayout(module);
+    if (!dl) {
+      return std::nullopt;
+    }
+    fir::LLVMTypeConverter typeConverter(module, /*applyTBAA=*/false,
+        /*forceUnifiedTBAATree=*/false, *dl);
+    std::optional<std::pair<uint64_t, unsigned short>> sizeAndAlignment =
+        fir::getTypeSizeAndAlignment(
+            UnknownLoc::get(&context), ty, *dl, typeConverter.getKindMap());
+    if (!sizeAndAlignment) {
+      return std::nullopt;
+    }
+    return acc::TypeSizeAndAlignment{
+        llvm::TypeSize::getFixed(sizeAndAlignment->first),
+        llvm::TypeSize::getFixed(sizeAndAlignment->second)};
+  }
+
+  MLIRContext context;
+  std::unique_ptr<fir::KindMapping> kindMap;
+  ModuleOp module;
+  acc::OpenACCSupport support;
+};
+
+TEST_F(FIROpenACCSupportAnalysisTest, FIRLogicalScalarSizeAndAlignment) {
+  Type logicalTy = fir::LogicalType::get(&context, /*kind=*/4);
+  std::optional<acc::TypeSizeAndAlignment> result =
+      support.getTypeSizeAndAlignment(logicalTy, module);
+  std::optional<acc::TypeSizeAndAlignment> expected =
+      getExpectedFIRSize(logicalTy);
+  ASSERT_TRUE(result.has_value());
+  ASSERT_TRUE(expected.has_value());
+  EXPECT_EQ(result->first, expected->first);
+  EXPECT_EQ(result->second, expected->second);
+}
+
+TEST_F(FIROpenACCSupportAnalysisTest, FIRCharacterScalarSizeAndAlignment) {
+  Type charTy = fir::CharacterType::get(&context, /*kind=*/1, /*len=*/8);
+  std::optional<acc::TypeSizeAndAlignment> result =
+      support.getTypeSizeAndAlignment(charTy, module);
+  std::optional<acc::TypeSizeAndAlignment> expected =
+      getExpectedFIRSize(charTy);
+  ASSERT_TRUE(result.has_value());
+  ASSERT_TRUE(expected.has_value());
+  EXPECT_EQ(result->first, expected->first);
+  EXPECT_EQ(result->second, expected->second);
+}
+
+TEST_F(FIROpenACCSupportAnalysisTest, FIRReferenceTypeUsesPointerSize) {
+  Type logicalTy = fir::LogicalType::get(&context, /*kind=*/4);
+  Type refTy = fir::ReferenceType::get(logicalTy);
+  std::optional<acc::TypeSizeAndAlignment> result =
+      support.getTypeSizeAndAlignment(refTy, module);
+  LLVM::LLVMPointerType ptrTy = LLVM::LLVMPointerType::get(&context);
+  std::optional<acc::TypeSizeAndAlignment> expected =
+      acc::getTypeSizeAndAlignment(ptrTy, module);
+  ASSERT_TRUE(result.has_value());
+  ASSERT_TRUE(expected.has_value());
+  EXPECT_EQ(result->first, expected->first);
+  EXPECT_EQ(result->second, expected->second);
+}
+
+TEST_F(FIROpenACCSupportAnalysisTest, BuiltinTypeDelegatesToAccUtilities) {
+  Type i32 = IntegerType::get(&context, 32);
+  std::optional<acc::TypeSizeAndAlignment> result =
+      support.getTypeSizeAndAlignment(i32, module);
+  std::optional<acc::TypeSizeAndAlignment> expected =
+      acc::getTypeSizeAndAlignment(i32, module);
+  ASSERT_TRUE(result.has_value());
+  ASSERT_TRUE(expected.has_value());
+  DataLayout dl(module);
+  EXPECT_EQ(result->first, dl.getTypeSize(i32));
+  EXPECT_EQ(result->second.getFixedValue(), dl.getTypeABIAlignment(i32));
+  EXPECT_EQ(result->first, expected->first);
+  EXPECT_EQ(result->second, expected->second);
+}
+
+TEST_F(FIROpenACCSupportAnalysisTest, TupleWithFIRArrayMemberSizeAndAlignment) {
+  Type f32 = Float32Type::get(&context);
+  Type seqTy = fir::SequenceType::get({1024}, f32);
+  Type tupleTy = TupleType::get(&context, {seqTy});
+  std::optional<acc::TypeSizeAndAlignment> result =
+      support.getTypeSizeAndAlignment(tupleTy, module);
+  std::optional<acc::TypeSizeAndAlignment> expected = getExpectedFIRSize(seqTy);
+  ASSERT_TRUE(result.has_value());
+  ASSERT_TRUE(expected.has_value());
+  EXPECT_EQ(result->first, expected->first);
+  EXPECT_EQ(result->second, expected->second);
+}
+
+TEST_F(FIROpenACCSupportAnalysisTest, FIRBoxTypeSizeAndAlignment) {
+  Type f32 = Float32Type::get(&context);
+  Type seqTy = fir::SequenceType::get({4, 3}, f32);
+  Type boxTy = fir::BoxType::get(seqTy);
+  std::optional<acc::TypeSizeAndAlignment> result =
+      support.getTypeSizeAndAlignment(boxTy, module);
+  ASSERT_TRUE(result.has_value());
+
+  std::optional<DataLayout> dl = acc::getDataLayout(module);
+  ASSERT_TRUE(dl.has_value());
+  fir::LLVMTypeConverter typeConverter(module, /*applyTBAA=*/false,
+      /*forceUnifiedTBAATree=*/false, *dl);
+  Type structTy =
+      typeConverter.convertBoxTypeAsStruct(cast<fir::BaseBoxType>(boxTy));
+  std::optional<acc::TypeSizeAndAlignment> expected =
+      acc::getTypeSizeAndAlignment(structTy, module, *dl, &support);
+  ASSERT_TRUE(expected.has_value());
+  EXPECT_EQ(result->first, expected->first);
+  EXPECT_EQ(result->second, expected->second);
+}
+
+} // namespace
diff --git a/mlir/include/mlir/Dialect/OpenACC/Analysis/OpenACCSupport.h b/mlir/include/mlir/Dialect/OpenACC/Analysis/OpenACCSupport.h
index 8649160aa46d7..32fd27f427f32 100644
--- a/mlir/include/mlir/Dialect/OpenACC/Analysis/OpenACCSupport.h
+++ b/mlir/include/mlir/Dialect/OpenACC/Analysis/OpenACCSupport.h
@@ -53,12 +53,15 @@
 #include "mlir/Dialect/GPU/IR/GPUDialect.h"
 #include "mlir/Dialect/OpenACC/OpenACCUtils.h"
 #include "mlir/Dialect/OpenACC/OpenACCUtilsGPU.h"
+#include "mlir/Dialect/OpenACC/OpenACCUtilsType.h"
+#include "mlir/IR/BuiltinOps.h"
 #include "mlir/IR/Remarks.h"
 #include "mlir/IR/Value.h"
 #include "mlir/Pass/AnalysisManager.h"
 #include "llvm/ADT/StringRef.h"
 #include <functional>
 #include <memory>
+#include <optional>
 #include <string>
 
 namespace mlir {
@@ -101,6 +104,11 @@ struct OpenACCSupportTraits {
     /// Get or optionally create a GPU module in the given module.
     virtual std::optional<gpu::GPUModuleOp>
     getOrCreateGPUModule(ModuleOp mod, bool create, llvm::StringRef name) = 0;
+
+    /// Returns the size and ABI alignment in bytes for \p ty.
+    virtual std::optional<TypeSizeAndAlignment>
+    getTypeSizeAndAlignment(Type ty, ModuleOp module,
+                            OpenACCSupport &support) = 0;
   };
 
   /// SFINAE helpers to detect if implementation has optional methods
@@ -141,6 +149,16 @@ struct OpenACCSupportTraits {
       llvm::is_detected<getOrCreateGPUModule_t, ImplT, ModuleOp, bool,
                         llvm::StringRef>;
 
+  template <typename ImplT, typename... Args>
+  using getTypeSizeAndAlignment_t =
+      decltype(std::declval<ImplT>().getTypeSizeAndAlignment(
+          std::declval<Args>()...));
+
+  template <typename ImplT>
+  using has_getTypeSizeAndAlignment =
+      llvm::is_detected<getTypeSizeAndAlignment_t, ImplT, Type, ModuleOp,
+                        OpenACCSupport &>;
+
   /// This class wraps a concrete OpenACCSupport implementation and forwards
   /// interface calls to it. This provides type erasure, allowing different
   /// implementation types to be used interchangeably without inheritance.
@@ -197,6 +215,15 @@ struct OpenACCSupportTraits {
         return acc::getOrCreateGPUModule(mod, create, name);
     }
 
+    std::optional<TypeSizeAndAlignment>
+    getTypeSizeAndAlignment(Type ty, ModuleOp module,
+                            OpenACCSupport &support) final {
+      if constexpr (has_getTypeSizeAndAlignment<ImplT>::value)
+        return impl.getTypeSizeAndAlignment(ty, module, support);
+      else
+        return acc::getTypeSizeAndAlignment(ty, module, &support);
+    }
+
   private:
     ImplT impl;
   };
@@ -307,6 +334,16 @@ class OpenACCSupport {
   getOrCreateGPUModule(ModuleOp mod, bool create = true,
                        llvm::StringRef name = "");
 
+  /// Returns the size and ABI alignment in bytes for \p ty.
+  std::optional<TypeSizeAndAlignment> getTypeSizeAndAlignment(Type ty,
+                                                              ModuleOp module) {
+    if (impl) {
+      if (auto result = impl->getTypeSizeAndAlignment(ty, module, *this))
+        return result;
+    }
+    return acc::getTypeSizeAndAlignment(ty, module, this);
+  }
+
   /// Signal that this analysis should always be preserved so that
   /// underlying implementation registration is not lost.
   bool isInvalidated(const AnalysisManager::PreservedAnalyses &pa) {
diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCUtilsType.h b/mlir/include/mlir/Dialect/OpenACC/OpenACCUtilsType.h
new file mode 100644
index 0000000000000..6fac3ad715ae4
--- /dev/null
+++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCUtilsType.h
@@ -0,0 +1,56 @@
+//===- OpenACCUtilsType.h - OpenACC Type Utilities -------------*- C++ -*-===//
+//
+// 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 file defines type utilities for OpenACC.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_DIALECT_OPENACC_OPENACCUTILSTYPE_H_
+#define MLIR_DIALECT_OPENACC_OPENACCUTILSTYPE_H_
+
+#include "llvm/Support/TypeSize.h"
+#include <optional>
+#include <utility>
+
+namespace mlir {
+class DataLayout;
+class ModuleOp;
+class Type;
+
+namespace acc {
+
+class OpenACCSupport;
+
+using TypeSizeAndAlignment = std::pair<llvm::TypeSize, llvm::TypeSize>;
+
+/// Returns the size and ABI alignment in bytes.
+///
+/// For aggregate structures and arrays, padding between members or elements is
+/// not taken into account. The result is a close estimate suitable for early
+/// OpenACC layout decisions, but not a complete ABI guarantee. For final size
+/// computations, use LLVM materialized types.
+///
+/// When \p support is provided, aggregate element types are sized by recursing
+/// through \p support so dialect-specific implementations can handle nested
+/// types.
+///
+/// Returns std::nullopt when the size is not statically computable or the type
+/// is not supported.
+std::optional<TypeSizeAndAlignment> getTypeSizeAndAlignment(
+    Type ty, ModuleOp module, const DataLayout &dl,
+    OpenACCSupport *support = nullptr);
+
+/// Same as above, obtaining \p dl from \p module via getDataLayout.
+std::optional<TypeSizeAndAlignment>
+getTypeSizeAndAlignment(Type ty, ModuleOp module,
+                        OpenACCSupport *support = nullptr);
+
+} // namespace acc
+} // namespace mlir
+
+#endif // MLIR_DIALECT_OPENACC_OPENACCUTILSTYPE_H_
diff --git a/mlir/lib/Dialect/OpenACC/Analysis/OpenACCSupport.cpp b/mlir/lib/Dialect/OpenACC/Analysis/OpenACCSupport.cpp
index 3875122152194..0f2f9d02ef2b3 100644
--- a/mlir/lib/Dialect/OpenACC/Analysis/OpenACCSupport.cpp
+++ b/mlir/lib/Dialect/OpenACC/Analysis/OpenACCSupport.cpp
@@ -13,6 +13,7 @@
 #include "mlir/Dialect/OpenACC/Analysis/OpenACCSupport.h"
 #include "mlir/Dialect/OpenACC/OpenACCUtils.h"
 #include "mlir/Dialect/OpenACC/OpenACCUtilsGPU.h"
+#include "mlir/Dialect/OpenACC/OpenACCUtilsType.h"
 
 namespace mlir {
 namespace acc {
diff --git a/mlir/lib/Dialect/OpenACC/Utils/CMakeLists.txt b/mlir/lib/Dialect/OpenACC/Utils/CMakeLists.txt
index baf248fd9b2ae..67e1fc269ffa4 100644
--- a/mlir/lib/Dialect/OpenACC/Utils/CMakeLists.txt
+++ b/mlir/lib/Dialect/OpenACC/Utils/CMakeLists.txt
@@ -4,6 +4,7 @@ add_mlir_dialect_library(MLIROpenACCUtils
   OpenACCUtilsGPU.cpp
   OpenACCUtilsLoop.cpp
   OpenACCUtilsTiling.cpp
+  OpenACCUtilsType.cpp
 
   ADDITIONAL_HEADER_DIRS
   ${MLIR_MAIN_INCLUDE_DIR}/mlir/Dialect/OpenACC
diff --git a/mlir/lib/Dialect/OpenACC/Utils/OpenACCUtilsType.cpp b/mlir/lib/Dialect/OpenACC/Utils/OpenACCUtilsType.cpp
new file mode 100644
index 0000000000000..ae43006c65a26
--- /dev/null
+++ b/mlir/lib/Dialect/OpenACC/Utils/OpenACCUtilsType.cpp
@@ -0,0 +1,94 @@
+//===- OpenACCUtilsType.cpp - OpenACC Type Utilities ----------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/Dialect/OpenACC/OpenACCUtilsType.h"
+#include "mlir/Dialect/LLVMIR/LLVMTypes.h"
+#include "mlir/Dialect/MemRef/IR/MemRef.h"
+#include "mlir/Dialect/OpenACC/Analysis/OpenACCSupport.h"
+#include "mlir/Dialect/OpenACC/OpenACCUtilsCG.h"
+#include "mlir/IR/BuiltinOps.h"
+#include "mlir/IR/BuiltinTypes.h"
+#include "mlir/Interfaces/DataLayoutInterfaces.h"
+
+namespace mlir {
+namespace acc {
+
+static std::optional<TypeSizeAndAlignment>
+getTypeSizeAndAlignmentHelper(Type ty, ModuleOp module, const DataLayout &dl,
+                              OpenACCSupport *support) {
+  if (support)
+    return support->getTypeSizeAndAlignment(ty, module);
+  return getTypeSizeAndAlignment(ty, module, dl);
+}
+
+std::optional<TypeSizeAndAlignment>
+getTypeSizeAndAlignment(Type ty, ModuleOp module, const DataLayout &dl,
+                        OpenACCSupport *support) {
+  if (ty.isIntOrIndexOrFloat() ||
+      isa<ComplexType, VectorType, DataLayoutTypeInterface>(ty)) {
+    return TypeSizeAndAlignment{
+        dl.getTypeSize(ty),
+        llvm::TypeSize::getFixed(dl.getTypeABIAlignment(ty))};
+  }
+
+  // Product of element size and static dimensions; no inter-element padding or
+  // array alignment rules are applied. This is acceptable as per API
+  // documentation.
+  if (auto memrefTy = dyn_cast<MemRefType>(ty)) {
+    if (!memrefTy.hasStaticShape())
+      return std::nullopt;
+    auto elemSizeAndAlignment = getTypeSizeAndAlignmentHelper(
+        memrefTy.getElementType(), module, dl, support);
+    if (!elemSizeAndAlignment)
+      return std::nullopt;
+    int64_t totalSize = elemSizeAndAlignment->first.getFixedValue();
+    int64_t alignment = elemSizeAndAlignment->second.getFixedValue();
+    for (int64_t dim : memrefTy.getShape())
+      totalSize *= dim;
+    return TypeSizeAndAlignment{llvm::TypeSize::getFixed(totalSize),
+                                llvm::TypeSize::getFixed(alignment)};
+  }
+
+  // Sum of member sizes with no padding between members or tuple alignment
+  // rules applied. This is acceptable as per API documentation.
+  if (auto tupleTy = dyn_cast<TupleType>(ty)) {
+    if (tupleTy.size() == 0)
+      return std::nullopt;
+    auto sizeAndAlignment =
+        getTypeSizeAndAlignmentHelper(tupleTy.getType(0), module, dl, support);
+    if (!sizeAndAlignment)
+      return std::nullopt;
+    llvm::TypeSize size = sizeAndAlignment->first;
+    for (unsigned i = 1, e = tupleTy.size(); i < e; ++i) {
+      auto next = getTypeSizeAndAlignmentHelper(tupleTy.getType(i), module, dl,
+                                                support);
+      if (!next)
+        return std::nullopt;
+      size += next->first;
+    }
+    return TypeSizeAndAlignment{size, sizeAndAlignment->second};
+  }
+
+  if (isa<FunctionType>(ty)) {
+    return getTypeSizeAndAlignmentHelper(
+        LLVM::LLVMPointerType::get(ty.getContext()), module, dl, support);
+  }
+
+  return std::nullopt;
+}
+
+std::optional<TypeSizeAndAlignment>
+getTypeSizeAndAlignment(Type ty, ModuleOp module, OpenACCSupport *support) {
+  std::optional<DataLayout> dl = getDataLayout(module);
+  if (!dl)
+    return std::nullopt;
+  return getTypeSizeAndAlignment(ty, module, *dl, support);
+}
+
+} // namespace acc
+} // namespace mlir
diff --git a/mlir/unittests/Dialect/OpenACC/CMakeLists.txt b/mlir/unittests/Dialect/OpenACC/CMakeLists.txt
index 7bcb652b69185..3a14d3e6796cb 100644
--- a/mlir/unittests/Dialect/OpenACC/CMakeLists.txt
+++ b/mlir/unittests/Dialect/OpenACC/CMakeLists.txt
@@ -6,6 +6,7 @@ add_mlir_unittest(MLIROpenACCTests
   OpenACCUtilsCGTest.cpp
   OpenACCUtilsGPUTest.cpp
   OpenACCUtilsTest.cpp
+  OpenACCUtilsTypeTest.cpp
   OpenACCUtilsTilingTest.cpp
   OpenACCUtilsLoopTest.cpp
 )
diff --git a/mlir/unittests/Dialect/OpenACC/OpenACCUtilsTypeTest.cpp b/mlir/unittests/Dialect/OpenACC/OpenACCUtilsTypeTest.cpp
new file mode 100644
index 0000000000000..9b178688749c4
--- /dev/null
+++ b/mlir/unittests/Dialect/OpenACC/OpenACCUtilsTypeTest.cpp
@@ -0,0 +1,83 @@
+//===- OpenACCUtilsTypeTest.cpp - Unit tests for OpenACC type utilities ---===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/Dialect/OpenACC/OpenACCUtilsType.h"
+#include "mlir/Dialect/DLTI/DLTI.h"
+#include "mlir/Dialect/Func/IR/FuncOps.h"
+#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
+#include "mlir/Dialect/MemRef/IR/MemRef.h"
+#include "mlir/IR/BuiltinOps.h"
+#include "mlir/IR/BuiltinTypes.h"
+#include "mlir/IR/MLIRContext.h"
+#include "mlir/IR/OwningOpRef.h"
+#include "mlir/Interfaces/DataLayoutInterfaces.h"
+#include "gtest/gtest.h"
+
+using namespace mlir;
+using namespace mlir::acc;
+
+class OpenACCUtilsTypeTest : public ::testing::Test {
+protected:
+  OpenACCUtilsTypeTest() : b(&context), loc(UnknownLoc::get(&context)) {
+    context.loadDialect<DLTIDialect, func::FuncDialect, memref::MemRefDialect,
+                        LLVM::LLVMDialect>();
+  }
+
+  MLIRContext context;
+  OpBuilder b;
+  Location loc;
+};
+
+TEST_F(OpenACCUtilsTypeTest, IntegerTypeSizeAndAlignment) {
+  OwningOpRef<ModuleOp> module = ModuleOp::create(b, loc);
+  auto i32 = b.getI32Type();
+  auto result = getTypeSizeAndAlignment(i32, *module);
+  ASSERT_TRUE(result.has_value());
+  DataLayout dl(*module);
+  EXPECT_EQ(result->first, dl.getTypeSize(i32));
+  EXPECT_EQ(result->second.getFixedValue(), dl.getTypeABIAlignment(i32));
+}
+
+TEST_F(OpenACCUtilsTypeTest, StaticMemRefTypeSizeAndAlignment) {
+  OwningOpRef<ModuleOp> module = ModuleOp::create(b, loc);
+  auto f64 = b.getF64Type();
+  auto memrefTy = MemRefType::get({4, 3}, f64);
+  auto result = getTypeSizeAndAlignment(memrefTy, *module);
+  ASSERT_TRUE(result.has_value());
+  DataLayout dl(*module);
+  EXPECT_EQ(result->first,
+            llvm::TypeSize::getFixed(dl.getTypeSize(f64).getFixedValue() * 12));
+  EXPECT_EQ(result->second.getFixedValue(), dl.getTypeABIAlignment(f64));
+}
+
+TEST_F(OpenACCUtilsTypeTest, VectorTypeUsesDataLayout) {
+  OwningOpRef<ModuleOp> module = ModuleOp::create(b, loc);
+  auto vectorTy = VectorType::get({3}, b.getF32Type());
+  auto result = getTypeSizeAndAlignment(vectorTy, *module);
+  ASSERT_TRUE(result.has_value());
+  DataLayout dl(*module);
+  EXPECT_EQ(result->first, dl.getTypeSize(vectorTy));
+  EXPECT_EQ(result->second.getFixedValue(), dl.getTypeABIAlignment(vectorTy));
+}
+
+TEST_F(OpenACCUtilsTypeTest, FunctionTypeUsesPointerSize) {
+  OwningOpRef<ModuleOp> module = ModuleOp::create(b, loc);
+  auto funcTy = b.getFunctionType({}, {});
+  auto ptrResult = getTypeSizeAndAlignment(funcTy, *module);
+  auto ptrTy = mlir::LLVM::LLVMPointerType::get(&context);
+  auto directPtrResult = getTypeSizeAndAlignment(ptrTy, *module);
+  ASSERT_TRUE(ptrResult.has_value());
+  ASSERT_TRUE(directPtrResult.has_value());
+  EXPECT_EQ(ptrResult->first, directPtrResult->first);
+}
+
+TEST_F(OpenACCUtilsTypeTest, DynamicMemRefReturnsNullopt) {
+  OwningOpRef<ModuleOp> module = ModuleOp::create(b, loc);
+  auto memrefTy = MemRefType::get({ShapedType::kDynamic}, b.getI32Type());
+  EXPECT_FALSE(getTypeSizeAndAlignment(memrefTy, *module).has_value());
+}

>From 71f31c636bb0c637b25ddbc6ed3b987538851639 Mon Sep 17 00:00:00 2001
From: Razvan Lupusoru <rlupusoru at nvidia.com>
Date: Tue, 7 Jul 2026 12:24:43 -0700
Subject: [PATCH 2/3] Fix formatting

---
 .../Optimizer/OpenACC/Analysis/FIROpenACCSupportAnalysis.h  | 2 +-
 mlir/include/mlir/Dialect/OpenACC/OpenACCUtilsType.h        | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/flang/include/flang/Optimizer/OpenACC/Analysis/FIROpenACCSupportAnalysis.h b/flang/include/flang/Optimizer/OpenACC/Analysis/FIROpenACCSupportAnalysis.h
index 8d2a90d3520d1..29706edb9c637 100644
--- a/flang/include/flang/Optimizer/OpenACC/Analysis/FIROpenACCSupportAnalysis.h
+++ b/flang/include/flang/Optimizer/OpenACC/Analysis/FIROpenACCSupportAnalysis.h
@@ -54,7 +54,7 @@ class FIROpenACCSupportAnalysis {
 
   std::optional<mlir::acc::TypeSizeAndAlignment>
   getTypeSizeAndAlignment(mlir::Type ty, mlir::ModuleOp module,
-                            mlir::acc::OpenACCSupport &support);
+                          mlir::acc::OpenACCSupport &support);
 };
 
 } // namespace acc
diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCUtilsType.h b/mlir/include/mlir/Dialect/OpenACC/OpenACCUtilsType.h
index 6fac3ad715ae4..42915ac954e7d 100644
--- a/mlir/include/mlir/Dialect/OpenACC/OpenACCUtilsType.h
+++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCUtilsType.h
@@ -41,9 +41,9 @@ using TypeSizeAndAlignment = std::pair<llvm::TypeSize, llvm::TypeSize>;
 ///
 /// Returns std::nullopt when the size is not statically computable or the type
 /// is not supported.
-std::optional<TypeSizeAndAlignment> getTypeSizeAndAlignment(
-    Type ty, ModuleOp module, const DataLayout &dl,
-    OpenACCSupport *support = nullptr);
+std::optional<TypeSizeAndAlignment>
+getTypeSizeAndAlignment(Type ty, ModuleOp module, const DataLayout &dl,
+                        OpenACCSupport *support = nullptr);
 
 /// Same as above, obtaining \p dl from \p module via getDataLayout.
 std::optional<TypeSizeAndAlignment>

>From e74fb5e02e27f37b5b2045e4b3352f3588336bc8 Mon Sep 17 00:00:00 2001
From: Razvan Lupusoru <rlupusoru at nvidia.com>
Date: Tue, 7 Jul 2026 12:48:43 -0700
Subject: [PATCH 3/3] Fix braces to match style

---
 .../OpenACC/Analysis/FIROpenACCSupportAnalysis.cpp          | 6 ++----
 .../Optimizer/OpenACC/FIROpenACCSupportAnalysisTest.cpp     | 6 ++----
 mlir/include/mlir/Dialect/OpenACC/Analysis/OpenACCSupport.h | 3 +--
 mlir/lib/Dialect/OpenACC/Utils/OpenACCUtilsType.cpp         | 6 ++----
 4 files changed, 7 insertions(+), 14 deletions(-)

diff --git a/flang/lib/Optimizer/OpenACC/Analysis/FIROpenACCSupportAnalysis.cpp b/flang/lib/Optimizer/OpenACC/Analysis/FIROpenACCSupportAnalysis.cpp
index df6202563a461..62f3a7dd44a6f 100644
--- a/flang/lib/Optimizer/OpenACC/Analysis/FIROpenACCSupportAnalysis.cpp
+++ b/flang/lib/Optimizer/OpenACC/Analysis/FIROpenACCSupportAnalysis.cpp
@@ -99,10 +99,9 @@ FIROpenACCSupportAnalysis::getTypeSizeAndAlignment(
   if (!dl)
     return std::nullopt;
 
-  if (isa<fir::ReferenceType, fir::HeapType, fir::LLVMPointerType>(ty)) {
+  if (isa<fir::ReferenceType, fir::HeapType, fir::LLVMPointerType>(ty))
     return mlir::acc::getTypeSizeAndAlignment(
         LLVM::LLVMPointerType::get(ty.getContext()), module, *dl, &support);
-  }
 
   if (!fir::isa_fir_type(ty))
     return mlir::acc::getTypeSizeAndAlignment(ty, module, *dl, &support);
@@ -111,10 +110,9 @@ FIROpenACCSupportAnalysis::getTypeSizeAndAlignment(
                                        /*forceUnifiedTBAATree=*/false, *dl);
   fir::KindMapping kindMap = typeConverter.getKindMap();
 
-  if (auto boxTy = dyn_cast<fir::BaseBoxType>(ty)) {
+  if (auto boxTy = dyn_cast<fir::BaseBoxType>(ty))
     return mlir::acc::getTypeSizeAndAlignment(
         typeConverter.convertBoxTypeAsStruct(boxTy), module, *dl, &support);
-  }
 
   auto sizeAndAlignment = fir::getTypeSizeAndAlignment(
       UnknownLoc::get(ty.getContext()), ty, *dl, kindMap);
diff --git a/flang/unittests/Optimizer/OpenACC/FIROpenACCSupportAnalysisTest.cpp b/flang/unittests/Optimizer/OpenACC/FIROpenACCSupportAnalysisTest.cpp
index 89454a48ede34..d00aef28d290a 100644
--- a/flang/unittests/Optimizer/OpenACC/FIROpenACCSupportAnalysisTest.cpp
+++ b/flang/unittests/Optimizer/OpenACC/FIROpenACCSupportAnalysisTest.cpp
@@ -37,17 +37,15 @@ struct FIROpenACCSupportAnalysisTest : public testing::Test {
 
   std::optional<acc::TypeSizeAndAlignment> getExpectedFIRSize(Type ty) {
     std::optional<DataLayout> dl = acc::getDataLayout(module);
-    if (!dl) {
+    if (!dl)
       return std::nullopt;
-    }
     fir::LLVMTypeConverter typeConverter(module, /*applyTBAA=*/false,
         /*forceUnifiedTBAATree=*/false, *dl);
     std::optional<std::pair<uint64_t, unsigned short>> sizeAndAlignment =
         fir::getTypeSizeAndAlignment(
             UnknownLoc::get(&context), ty, *dl, typeConverter.getKindMap());
-    if (!sizeAndAlignment) {
+    if (!sizeAndAlignment)
       return std::nullopt;
-    }
     return acc::TypeSizeAndAlignment{
         llvm::TypeSize::getFixed(sizeAndAlignment->first),
         llvm::TypeSize::getFixed(sizeAndAlignment->second)};
diff --git a/mlir/include/mlir/Dialect/OpenACC/Analysis/OpenACCSupport.h b/mlir/include/mlir/Dialect/OpenACC/Analysis/OpenACCSupport.h
index 32fd27f427f32..03bb6fb81d1ed 100644
--- a/mlir/include/mlir/Dialect/OpenACC/Analysis/OpenACCSupport.h
+++ b/mlir/include/mlir/Dialect/OpenACC/Analysis/OpenACCSupport.h
@@ -337,10 +337,9 @@ class OpenACCSupport {
   /// Returns the size and ABI alignment in bytes for \p ty.
   std::optional<TypeSizeAndAlignment> getTypeSizeAndAlignment(Type ty,
                                                               ModuleOp module) {
-    if (impl) {
+    if (impl)
       if (auto result = impl->getTypeSizeAndAlignment(ty, module, *this))
         return result;
-    }
     return acc::getTypeSizeAndAlignment(ty, module, this);
   }
 
diff --git a/mlir/lib/Dialect/OpenACC/Utils/OpenACCUtilsType.cpp b/mlir/lib/Dialect/OpenACC/Utils/OpenACCUtilsType.cpp
index ae43006c65a26..5761e853c650c 100644
--- a/mlir/lib/Dialect/OpenACC/Utils/OpenACCUtilsType.cpp
+++ b/mlir/lib/Dialect/OpenACC/Utils/OpenACCUtilsType.cpp
@@ -30,11 +30,10 @@ std::optional<TypeSizeAndAlignment>
 getTypeSizeAndAlignment(Type ty, ModuleOp module, const DataLayout &dl,
                         OpenACCSupport *support) {
   if (ty.isIntOrIndexOrFloat() ||
-      isa<ComplexType, VectorType, DataLayoutTypeInterface>(ty)) {
+      isa<ComplexType, VectorType, DataLayoutTypeInterface>(ty))
     return TypeSizeAndAlignment{
         dl.getTypeSize(ty),
         llvm::TypeSize::getFixed(dl.getTypeABIAlignment(ty))};
-  }
 
   // Product of element size and static dimensions; no inter-element padding or
   // array alignment rules are applied. This is acceptable as per API
@@ -74,10 +73,9 @@ getTypeSizeAndAlignment(Type ty, ModuleOp module, const DataLayout &dl,
     return TypeSizeAndAlignment{size, sizeAndAlignment->second};
   }
 
-  if (isa<FunctionType>(ty)) {
+  if (isa<FunctionType>(ty))
     return getTypeSizeAndAlignmentHelper(
         LLVM::LLVMPointerType::get(ty.getContext()), module, dl, support);
-  }
 
   return std::nullopt;
 }



More information about the flang-commits mailing list