[clang] [CIR] Pointer and vptr width from a CIR-native data-layout entry (PR #204185)
Akshay K via cfe-commits
cfe-commits at lists.llvm.org
Mon Jun 29 14:45:55 PDT 2026
https://github.com/kumarak updated https://github.com/llvm/llvm-project/pull/204185
>From 260c76b7365ac3421c899cddf0beb1fb51992d42 Mon Sep 17 00:00:00 2001
From: AkshayK <iit.akshay at gmail.com>
Date: Tue, 16 Jun 2026 11:14:06 -0400
Subject: [PATCH 1/2] [CIR] Drive pointer and vptr width from a CIR-native
data-layout entry
PointerType and VPtrType hardcoded size/alignment to 64/8, aborting record
layout on 32-bit-pointer targets such as nvptx/spirv32. Attach a CIR-native
cir.ptr data-layout entry at module setup and read the pointer width from it,
so the CIR type system needs no LLVM-dialect dependency; the entry is stripped
during CIR->LLVM lowering. 64-bit targets are unchanged.
---
clang/lib/CIR/CodeGen/CIRGenerator.cpp | 25 ++++++++-
clang/lib/CIR/Dialect/IR/CIRTypes.cpp | 56 +++++++++++++++++--
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 17 ++++++
.../test/CIR/CodeGen/pointer-width-32bit.cpp | 44 +++++++++++++++
4 files changed, 135 insertions(+), 7 deletions(-)
create mode 100644 clang/test/CIR/CodeGen/pointer-width-32bit.cpp
diff --git a/clang/lib/CIR/CodeGen/CIRGenerator.cpp b/clang/lib/CIR/CodeGen/CIRGenerator.cpp
index d4fcbb6e42f3e..61efaebad9b82 100644
--- a/clang/lib/CIR/CodeGen/CIRGenerator.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenerator.cpp
@@ -21,6 +21,7 @@
#include "clang/AST/DeclGroup.h"
#include "clang/CIR/CIRGenerator.h"
#include "clang/CIR/InitAllDialects.h"
+#include "clang/CIR/MissingFeatures.h"
#include "llvm/IR/DataLayout.h"
using namespace cir;
@@ -42,7 +43,29 @@ static void setMLIRDataLayout(mlir::ModuleOp &mod, const llvm::DataLayout &dl) {
mlir::MLIRContext *mlirContext = mod.getContext();
mlir::DataLayoutSpecInterface dlSpec =
mlir::translateDataLayout(dl, mlirContext);
- mod->setAttr(mlir::DLTIDialect::kDataLayoutAttrName, dlSpec);
+
+ // Add a CIR-native pointer data-layout entry so cir.ptr / cir.vptr size and
+ // alignment are driven by the data layout rather than hardcoded.
+ // The value stores {size-in-bits, abi-align-in-bits} keyed on cir.ptr.
+ //
+ // TODO(cir): Only the default address space is recorded and
+ // address-space-dependent pointer sizes are not modeled yet. Emit
+ // per-address-space entries.
+ assert(!cir::MissingFeatures::dataLayoutPtrHandlingBasedOnLangAS());
+ constexpr unsigned kBitsInByte = 8;
+ unsigned ptrSizeBits = dl.getPointerSizeInBits(/*AS=*/0);
+ unsigned ptrAlignBits =
+ dl.getPointerABIAlignment(/*AS=*/0).value() * kBitsInByte;
+ auto ptrKey = cir::PointerType::get(cir::VoidType::get(mlirContext));
+ auto ptrVal = mlir::DenseI32ArrayAttr::get(
+ mlirContext,
+ {static_cast<int32_t>(ptrSizeBits), static_cast<int32_t>(ptrAlignBits)});
+ llvm::SmallVector<mlir::DataLayoutEntryInterface> entries(
+ dlSpec.getEntries().begin(), dlSpec.getEntries().end());
+ entries.push_back(mlir::DataLayoutEntryAttr::get(ptrKey, ptrVal));
+
+ mod->setAttr(mlir::DLTIDialect::kDataLayoutAttrName,
+ mlir::DataLayoutSpecAttr::get(mlirContext, entries));
}
void CIRGenerator::Initialize(ASTContext &astContext) {
diff --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
index 9c2a40e3681aa..04da6c85bbbb1 100644
--- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
@@ -580,20 +580,62 @@ void RecordType::removeABIConversionNamePrefix() {
// Data Layout information for types
//===----------------------------------------------------------------------===//
+// A CIR-native pointer data-layout entry stores {size-in-bits,
+// abi-align-in-bits} as a dense i32 array keyed on a cir.ptr type (see
+// setMLIRDataLayout in CIRGenerator).
+namespace {
+constexpr static uint64_t kBitsInByte = 8;
+
+// Defaults used only when the module carries no cir.ptr data-layout entry
+// (e.g. CIR parsed from text without a data layout). These mirror the MLIR LLVM
+// dialect's pointer defaults.
+constexpr static uint64_t kDefaultPointerSizeBits = 64;
+constexpr static uint64_t kDefaultPointerAlignment = 8;
+
+enum class CIRPtrDLPos { Size = 0, AbiAlign = 1 };
+
+// Returns the requested field of the cir.ptr data-layout entry.
+std::optional<uint64_t> getPointerSpecValue(mlir::DataLayoutEntryListRef params,
+ CIRPtrDLPos pos) {
+ for (mlir::DataLayoutEntryInterface entry : params) {
+ if (!entry.isTypeEntry())
+ continue;
+ auto spec = mlir::dyn_cast<mlir::DenseI32ArrayAttr>(entry.getValue());
+ assert(spec && spec.size() == 2 &&
+ "malformed cir.ptr data layout entry: expected a pair of i32 "
+ "{size-in-bits, abi-align-in-bits}");
+ return static_cast<uint64_t>(spec[static_cast<int>(pos)]);
+ }
+ return std::nullopt;
+}
+} // namespace
+
llvm::TypeSize
PointerType::getTypeSizeInBits(const ::mlir::DataLayout &dataLayout,
::mlir::DataLayoutEntryListRef params) const {
+ // The pointer width comes from the CIR-native data-layout entry keyed on
+ // cir.ptr, which records the width for the default address space; fall back
+ // to 64 bits if the module carries no such entry.
// FIXME: improve this in face of address spaces
assert(!cir::MissingFeatures::dataLayoutPtrHandlingBasedOnLangAS());
- return llvm::TypeSize::getFixed(64);
+ if (std::optional<uint64_t> size =
+ getPointerSpecValue(params, CIRPtrDLPos::Size))
+ return llvm::TypeSize::getFixed(*size);
+ return llvm::TypeSize::getFixed(kDefaultPointerSizeBits);
}
uint64_t
PointerType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
::mlir::DataLayoutEntryListRef params) const {
+ // As with the size, the alignment is taken from the default-address-space
+ // cir.ptr data-layout entry. Address-space-dependent alignments are not yet
+ // modeled.
// FIXME: improve this in face of address spaces
assert(!cir::MissingFeatures::dataLayoutPtrHandlingBasedOnLangAS());
- return 8;
+ if (std::optional<uint64_t> align =
+ getPointerSpecValue(params, CIRPtrDLPos::AbiAlign))
+ return *align / kBitsInByte;
+ return kDefaultPointerAlignment;
}
llvm::TypeSize
@@ -1112,14 +1154,16 @@ DataMemberType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
llvm::TypeSize
VPtrType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
mlir::DataLayoutEntryListRef params) const {
- // FIXME: consider size differences under different ABIs
- return llvm::TypeSize::getFixed(64);
+ // The vtable pointer is an ordinary data pointer; route the query through a
+ // cir.ptr so it picks up the same data-layout-driven width.
+ return dataLayout.getTypeSizeInBits(
+ cir::PointerType::get(cir::VoidType::get(getContext())));
}
uint64_t VPtrType::getABIAlignment(const mlir::DataLayout &dataLayout,
mlir::DataLayoutEntryListRef params) const {
- // FIXME: consider alignment differences under different ABIs
- return 8;
+ return dataLayout.getTypeABIAlignment(
+ cir::PointerType::get(cir::VoidType::get(getContext())));
}
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index e0fc9e58ed4b7..00c94b37e1a6c 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -3794,6 +3794,23 @@ void ConvertCIRToLLVMPass::runOnOperation() {
if (failed(applyPartialConversion(ops, target, std::move(patterns))))
signalPassFailure();
+ // The CIR-native pointer data-layout entry (keyed on cir.ptr) drives pointer
+ // widths during CIR codegen and lowering, but cir.ptr has no meaning once the
+ // module is translated to LLVM IR. Drop it so the resulting data layout only
+ // references LLVM types.
+ if (auto dlSpec = mlir::dyn_cast_or_null<mlir::DataLayoutSpecAttr>(
+ module->getAttr(mlir::DLTIDialect::kDataLayoutAttrName))) {
+ llvm::SmallVector<mlir::DataLayoutEntryInterface> kept;
+ for (mlir::DataLayoutEntryInterface entry : dlSpec.getEntries()) {
+ if (entry.isTypeEntry() &&
+ mlir::isa<cir::PointerType>(mlir::cast<mlir::Type>(entry.getKey())))
+ continue;
+ kept.push_back(entry);
+ }
+ module->setAttr(mlir::DLTIDialect::kDataLayoutAttrName,
+ mlir::DataLayoutSpecAttr::get(module.getContext(), kept));
+ }
+
// Emit the llvm.global_ctors array.
buildCtorDtorList(module, cir::CIRDialect::getGlobalCtorsAttrName(),
"llvm.global_ctors", [](mlir::Attribute attr) {
diff --git a/clang/test/CIR/CodeGen/pointer-width-32bit.cpp b/clang/test/CIR/CodeGen/pointer-width-32bit.cpp
new file mode 100644
index 0000000000000..15f3ec92d7e16
--- /dev/null
+++ b/clang/test/CIR/CodeGen/pointer-width-32bit.cpp
@@ -0,0 +1,44 @@
+// RUN: %clang_cc1 -std=c++20 -triple nvptx-nvidia-cuda -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
+// RUN: %clang_cc1 -std=c++20 -triple nvptx-nvidia-cuda -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s
+// RUN: %clang_cc1 -std=c++20 -triple nvptx-nvidia-cuda -emit-llvm %s -o %t.ll
+// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s
+
+// On a target with 32-bit pointers (e.g. nvptx) both a data pointer (!cir.ptr)
+// and the vtable pointer (!cir.vptr) are 4 bytes wide. The pointer width is
+// carried by a CIR-native data-layout entry keyed on cir.ptr, so the field
+// following a pointer lands at the AST-mandated offset. Sizing pointers as a
+// hardcoded 64 bits previously tripped the record layout builder (insertPadding:
+// assertion `offset >= size`) on every record containing a pointer.
+
+struct S {
+ int *p;
+ int x;
+};
+
+S s;
+
+class A {
+public:
+ virtual void f();
+ int x;
+};
+
+void A::f() {}
+
+// The module carries a CIR-native pointer data-layout entry ({size, abi-align}
+// in bits) that drives both cir.ptr and cir.vptr widths. The 4-byte pointer is
+// immediately followed by 'x' at offset 4 with no padding, and each record is
+// 4-byte aligned.
+// CIR-DAG: !rec_S = !cir.struct<"S" {!cir.ptr<!s32i>, !s32i}>
+// CIR-DAG: !rec_A = !cir.struct<class "A" {!cir.vptr, !s32i}>
+// CIR-DAG: !cir.ptr<!cir.void> = array<i32: 32, 32>
+// CIR: cir.global external @s = #cir.zero : !rec_S {alignment = 4 : i64}
+// CIR: cir.global{{.*}}@_ZTV1A = #cir.vtable<{{.*}}{alignment = 4 : i64}
+
+// LLVM: @s = global %struct.S zeroinitializer, align 4
+// LLVM: @_ZTV1A = global { [3 x ptr] } {{.*}}, align 4
+
+// OGCG: @s = global %struct.S zeroinitializer, align 4
+// OGCG: @_ZTV1A = {{.*}}constant { [3 x ptr] } {{.*}}, align 4
>From c6b7e8bb3ad6d1496c1aa60416ddc46a70de0ff0 Mon Sep 17 00:00:00 2001
From: AkshayK <iit.akshay at gmail.com>
Date: Mon, 29 Jun 2026 17:35:07 -0400
Subject: [PATCH 2/2] [CIR] Use #ptr.spec for pointer data-layout entry
Replace the dense-i32 cir.ptr DL entry with mlir::ptr::SpecAttr and
implement PointerType::verifyEntries/areCompatible.
---
.../include/clang/CIR/Dialect/IR/CIRTypes.td | 3 +-
clang/lib/CIR/CMakeLists.txt | 1 +
clang/lib/CIR/CodeGen/CIRGenerator.cpp | 28 ++++---
clang/lib/CIR/Dialect/IR/CIRTypes.cpp | 75 +++++++++++++------
clang/lib/CIR/Dialect/IR/CMakeLists.txt | 1 +
clang/lib/CIR/RegisterAllDialects.cpp | 4 +-
.../test/CIR/CodeGen/pointer-width-32bit.cpp | 6 +-
clang/test/CIR/IR/pointer-data-layout.cir | 16 ++++
8 files changed, 96 insertions(+), 38 deletions(-)
create mode 100644 clang/test/CIR/IR/pointer-data-layout.cir
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
index 95be236854338..a397a06a7d082 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td
@@ -239,7 +239,8 @@ def CIR_ComplexType : CIR_Type<"Complex", "complex", [
//===----------------------------------------------------------------------===//
def CIR_PointerType : CIR_Type<"Pointer", "ptr", [
- DeclareTypeInterfaceMethods<DataLayoutTypeInterface>,
+ DeclareTypeInterfaceMethods<DataLayoutTypeInterface,
+ ["verifyEntries", "areCompatible"]>,
DeclareTypeInterfaceMethods<CIR_SizedTypeInterface>
]> {
let summary = "CIR pointer type";
diff --git a/clang/lib/CIR/CMakeLists.txt b/clang/lib/CIR/CMakeLists.txt
index f215c927565de..4ff5b24c21fe8 100644
--- a/clang/lib/CIR/CMakeLists.txt
+++ b/clang/lib/CIR/CMakeLists.txt
@@ -26,4 +26,5 @@ add_clang_library(CIRRegisterAllDialects
CIROpenACCSupport
CIROpenMPSupport
MLIRDLTIDialect
+ MLIRPtrDialect
)
diff --git a/clang/lib/CIR/CodeGen/CIRGenerator.cpp b/clang/lib/CIR/CodeGen/CIRGenerator.cpp
index 61efaebad9b82..912d9f02eeabc 100644
--- a/clang/lib/CIR/CodeGen/CIRGenerator.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenerator.cpp
@@ -15,6 +15,8 @@
#include "mlir/Dialect/DLTI/DLTI.h"
#include "mlir/Dialect/OpenACC/OpenACC.h"
#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
+#include "mlir/Dialect/Ptr/IR/PtrAttrs.h"
+#include "mlir/Dialect/Ptr/IR/PtrDialect.h"
#include "mlir/IR/MLIRContext.h"
#include "mlir/Target/LLVMIR/Import.h"
@@ -44,25 +46,26 @@ static void setMLIRDataLayout(mlir::ModuleOp &mod, const llvm::DataLayout &dl) {
mlir::DataLayoutSpecInterface dlSpec =
mlir::translateDataLayout(dl, mlirContext);
- // Add a CIR-native pointer data-layout entry so cir.ptr / cir.vptr size and
- // alignment are driven by the data layout rather than hardcoded.
- // The value stores {size-in-bits, abi-align-in-bits} keyed on cir.ptr.
+ // Drive cir.ptr / cir.vptr size and alignment from the target data layout
+ // (rather than hardcoded), recorded as a #ptr.spec entry keyed on cir.ptr.
+ // Reusing mlir::ptr::SpecAttr gives us its structured verification (fields
+ // divisible by 8, preferred >= abi) at construction.
//
- // TODO(cir): Only the default address space is recorded and
- // address-space-dependent pointer sizes are not modeled yet. Emit
- // per-address-space entries.
+ // TODO(cir): Only the default address space is recorded. Emit one entry per
+ // address space once address-space-dependent pointer sizes are modeled.
assert(!cir::MissingFeatures::dataLayoutPtrHandlingBasedOnLangAS());
constexpr unsigned kBitsInByte = 8;
unsigned ptrSizeBits = dl.getPointerSizeInBits(/*AS=*/0);
- unsigned ptrAlignBits =
+ unsigned ptrAbiBits =
dl.getPointerABIAlignment(/*AS=*/0).value() * kBitsInByte;
+ unsigned ptrPrefBits =
+ dl.getPointerPrefAlignment(/*AS=*/0).value() * kBitsInByte;
auto ptrKey = cir::PointerType::get(cir::VoidType::get(mlirContext));
- auto ptrVal = mlir::DenseI32ArrayAttr::get(
- mlirContext,
- {static_cast<int32_t>(ptrSizeBits), static_cast<int32_t>(ptrAlignBits)});
+ auto ptrSpec = mlir::ptr::SpecAttr::get(mlirContext, ptrSizeBits, ptrAbiBits,
+ ptrPrefBits);
llvm::SmallVector<mlir::DataLayoutEntryInterface> entries(
dlSpec.getEntries().begin(), dlSpec.getEntries().end());
- entries.push_back(mlir::DataLayoutEntryAttr::get(ptrKey, ptrVal));
+ entries.push_back(mlir::DataLayoutEntryAttr::get(ptrKey, ptrSpec));
mod->setAttr(mlir::DLTIDialect::kDataLayoutAttrName,
mlir::DataLayoutSpecAttr::get(mlirContext, entries));
@@ -75,7 +78,8 @@ void CIRGenerator::Initialize(ASTContext &astContext) {
mlirContext = std::make_unique<mlir::MLIRContext>();
cir::registerAllDialects(*mlirContext);
- mlirContext->loadDialect<mlir::DLTIDialect, cir::CIRDialect>();
+ mlirContext->loadDialect<mlir::DLTIDialect, mlir::ptr::PtrDialect,
+ cir::CIRDialect>();
mlirContext->getOrLoadDialect<mlir::acc::OpenACCDialect>();
mlirContext->getOrLoadDialect<mlir::omp::OpenMPDialect>();
diff --git a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
index 04da6c85bbbb1..ff42d48d570ad 100644
--- a/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRTypes.cpp
@@ -13,6 +13,7 @@
#include "clang/CIR/Dialect/IR/CIRTypes.h"
#include "mlir/Dialect/Ptr/IR/MemorySpaceInterfaces.h"
+#include "mlir/Dialect/Ptr/IR/PtrAttrs.h"
#include "mlir/IR/BuiltinAttributes.h"
#include "mlir/IR/DialectImplementation.h"
#include "mlir/IR/MLIRContext.h"
@@ -580,9 +581,9 @@ void RecordType::removeABIConversionNamePrefix() {
// Data Layout information for types
//===----------------------------------------------------------------------===//
-// A CIR-native pointer data-layout entry stores {size-in-bits,
-// abi-align-in-bits} as a dense i32 array keyed on a cir.ptr type (see
-// setMLIRDataLayout in CIRGenerator).
+// The cir.ptr data-layout entry stores its width and alignment as an
+// mlir::ptr::SpecAttr keyed on a cir.ptr type (see setMLIRDataLayout in
+// CIRGenerator), reusing the ptr dialect's structured spec attribute.
namespace {
constexpr static uint64_t kBitsInByte = 8;
@@ -592,35 +593,29 @@ constexpr static uint64_t kBitsInByte = 8;
constexpr static uint64_t kDefaultPointerSizeBits = 64;
constexpr static uint64_t kDefaultPointerAlignment = 8;
-enum class CIRPtrDLPos { Size = 0, AbiAlign = 1 };
-
-// Returns the requested field of the cir.ptr data-layout entry.
-std::optional<uint64_t> getPointerSpecValue(mlir::DataLayoutEntryListRef params,
- CIRPtrDLPos pos) {
+// Returns the cir.ptr data-layout spec, if the module carries one. Iterates the
+// full entry list so additional per-address-space entries can be added later.
+mlir::ptr::SpecAttr getPointerSpec(mlir::DataLayoutEntryListRef params) {
for (mlir::DataLayoutEntryInterface entry : params) {
if (!entry.isTypeEntry())
continue;
- auto spec = mlir::dyn_cast<mlir::DenseI32ArrayAttr>(entry.getValue());
- assert(spec && spec.size() == 2 &&
- "malformed cir.ptr data layout entry: expected a pair of i32 "
- "{size-in-bits, abi-align-in-bits}");
- return static_cast<uint64_t>(spec[static_cast<int>(pos)]);
+ if (auto spec = mlir::dyn_cast<mlir::ptr::SpecAttr>(entry.getValue()))
+ return spec;
}
- return std::nullopt;
+ return {};
}
} // namespace
llvm::TypeSize
PointerType::getTypeSizeInBits(const ::mlir::DataLayout &dataLayout,
::mlir::DataLayoutEntryListRef params) const {
- // The pointer width comes from the CIR-native data-layout entry keyed on
+ // The pointer width comes from the #ptr.spec data-layout entry keyed on
// cir.ptr, which records the width for the default address space; fall back
// to 64 bits if the module carries no such entry.
// FIXME: improve this in face of address spaces
assert(!cir::MissingFeatures::dataLayoutPtrHandlingBasedOnLangAS());
- if (std::optional<uint64_t> size =
- getPointerSpecValue(params, CIRPtrDLPos::Size))
- return llvm::TypeSize::getFixed(*size);
+ if (mlir::ptr::SpecAttr spec = getPointerSpec(params))
+ return llvm::TypeSize::getFixed(spec.getSize());
return llvm::TypeSize::getFixed(kDefaultPointerSizeBits);
}
@@ -632,12 +627,50 @@ PointerType::getABIAlignment(const ::mlir::DataLayout &dataLayout,
// modeled.
// FIXME: improve this in face of address spaces
assert(!cir::MissingFeatures::dataLayoutPtrHandlingBasedOnLangAS());
- if (std::optional<uint64_t> align =
- getPointerSpecValue(params, CIRPtrDLPos::AbiAlign))
- return *align / kBitsInByte;
+ if (mlir::ptr::SpecAttr spec = getPointerSpec(params))
+ return spec.getAbi() / kBitsInByte;
return kDefaultPointerAlignment;
}
+llvm::LogicalResult
+PointerType::verifyEntries(mlir::DataLayoutEntryListRef entries,
+ mlir::Location loc) const {
+ // Every cir.ptr data-layout entry must carry a #ptr.spec value.
+ for (mlir::DataLayoutEntryInterface entry : entries) {
+ if (!entry.isTypeEntry())
+ continue;
+ if (!mlir::isa<mlir::ptr::SpecAttr>(entry.getValue())) {
+ auto key = mlir::cast<mlir::Type>(entry.getKey());
+ return mlir::emitError(loc) << "expected layout attribute for " << key
+ << " to be a #ptr.spec attribute";
+ }
+ }
+ return mlir::success();
+}
+
+bool PointerType::areCompatible(
+ mlir::DataLayoutEntryListRef oldLayout,
+ mlir::DataLayoutEntryListRef newLayout, mlir::DataLayoutSpecInterface,
+ const mlir::DataLayoutIdentifiedEntryMap &) const {
+ // A nested layout may override the pointer spec only if it keeps the same
+ // size and an ABI alignment that the outer alignment can satisfy.
+ for (mlir::DataLayoutEntryInterface newEntry : newLayout) {
+ if (!newEntry.isTypeEntry())
+ continue;
+ uint64_t size = kDefaultPointerSizeBits;
+ uint64_t abi = kDefaultPointerAlignment * kBitsInByte;
+ if (mlir::ptr::SpecAttr oldSpec = getPointerSpec(oldLayout)) {
+ size = oldSpec.getSize();
+ abi = oldSpec.getAbi();
+ }
+ auto newSpec = mlir::cast<mlir::ptr::SpecAttr>(newEntry.getValue());
+ if (size != newSpec.getSize() || abi < newSpec.getAbi() ||
+ abi % newSpec.getAbi() != 0)
+ return false;
+ }
+ return true;
+}
+
llvm::TypeSize
StructType::getTypeSizeInBits(const mlir::DataLayout &dataLayout,
mlir::DataLayoutEntryListRef params) const {
diff --git a/clang/lib/CIR/Dialect/IR/CMakeLists.txt b/clang/lib/CIR/Dialect/IR/CMakeLists.txt
index c8205ebeabf6c..eaf43401f41b7 100644
--- a/clang/lib/CIR/Dialect/IR/CMakeLists.txt
+++ b/clang/lib/CIR/Dialect/IR/CMakeLists.txt
@@ -18,6 +18,7 @@ add_clang_library(MLIRCIR
MLIRCIRInterfaces
MLIRDLTIDialect
MLIRDataLayoutInterfaces
+ MLIRPtrDialect
MLIRFuncDialect
MLIRLoopLikeInterface
MLIRCIRInterfaces
diff --git a/clang/lib/CIR/RegisterAllDialects.cpp b/clang/lib/CIR/RegisterAllDialects.cpp
index 8c2961bdebbaa..7a3ecb6ce30ef 100644
--- a/clang/lib/CIR/RegisterAllDialects.cpp
+++ b/clang/lib/CIR/RegisterAllDialects.cpp
@@ -11,6 +11,7 @@
#include "mlir/Dialect/DLTI/DLTI.h"
#include "mlir/Dialect/OpenACC/OpenACC.h"
#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
+#include "mlir/Dialect/Ptr/IR/PtrDialect.h"
#include "mlir/IR/BuiltinDialect.h"
#include "mlir/IR/MLIRContext.h"
@@ -22,7 +23,8 @@ namespace cir {
void registerAllDialects(mlir::DialectRegistry ®istry) {
registry.insert<mlir::BuiltinDialect, cir::CIRDialect, mlir::DLTIDialect,
- mlir::omp::OpenMPDialect, mlir::acc::OpenACCDialect>();
+ mlir::ptr::PtrDialect, mlir::omp::OpenMPDialect,
+ mlir::acc::OpenACCDialect>();
// Register extensions to integrate CIR types with OpenACC and OpenMP.
cir::omp::registerOpenMPExtensions(registry);
cir::acc::registerOpenACCExtensions(registry);
diff --git a/clang/test/CIR/CodeGen/pointer-width-32bit.cpp b/clang/test/CIR/CodeGen/pointer-width-32bit.cpp
index 15f3ec92d7e16..826fe5e6fcee1 100644
--- a/clang/test/CIR/CodeGen/pointer-width-32bit.cpp
+++ b/clang/test/CIR/CodeGen/pointer-width-32bit.cpp
@@ -7,7 +7,7 @@
// On a target with 32-bit pointers (e.g. nvptx) both a data pointer (!cir.ptr)
// and the vtable pointer (!cir.vptr) are 4 bytes wide. The pointer width is
-// carried by a CIR-native data-layout entry keyed on cir.ptr, so the field
+// carried by a #ptr.spec data-layout entry keyed on cir.ptr, so the field
// following a pointer lands at the AST-mandated offset. Sizing pointers as a
// hardcoded 64 bits previously tripped the record layout builder (insertPadding:
// assertion `offset >= size`) on every record containing a pointer.
@@ -27,13 +27,13 @@ class A {
void A::f() {}
-// The module carries a CIR-native pointer data-layout entry ({size, abi-align}
+// The module carries a #ptr.spec pointer data-layout entry (size/abi/preferred
// in bits) that drives both cir.ptr and cir.vptr widths. The 4-byte pointer is
// immediately followed by 'x' at offset 4 with no padding, and each record is
// 4-byte aligned.
// CIR-DAG: !rec_S = !cir.struct<"S" {!cir.ptr<!s32i>, !s32i}>
// CIR-DAG: !rec_A = !cir.struct<class "A" {!cir.vptr, !s32i}>
-// CIR-DAG: !cir.ptr<!cir.void> = array<i32: 32, 32>
+// CIR-DAG: !cir.ptr<!cir.void> = #ptr.spec<size = 32, abi = 32, preferred = 32>
// CIR: cir.global external @s = #cir.zero : !rec_S {alignment = 4 : i64}
// CIR: cir.global{{.*}}@_ZTV1A = #cir.vtable<{{.*}}{alignment = 4 : i64}
diff --git a/clang/test/CIR/IR/pointer-data-layout.cir b/clang/test/CIR/IR/pointer-data-layout.cir
new file mode 100644
index 0000000000000..207445d389284
--- /dev/null
+++ b/clang/test/CIR/IR/pointer-data-layout.cir
@@ -0,0 +1,16 @@
+// RUN: cir-opt %s -verify-diagnostics -split-input-file
+
+// The cir.ptr data-layout entry carries an mlir::ptr::SpecAttr (#ptr.spec).
+// A well-formed entry round-trips without diagnostics.
+module attributes {dlti.dl_spec = #dlti.dl_spec<
+ !cir.ptr<!cir.void> = #ptr.spec<size = 32, abi = 32, preferred = 32>>} {
+}
+
+// -----
+
+// PointerType::verifyEntries rejects a cir.ptr entry whose value is not a
+// #ptr.spec attribute.
+// expected-error @below {{expected layout attribute for '!cir.ptr<!cir.void>' to be a #ptr.spec attribute}}
+module attributes {dlti.dl_spec = #dlti.dl_spec<
+ !cir.ptr<!cir.void> = dense<32> : vector<2xi64>>} {
+}
More information about the cfe-commits
mailing list