[Mlir-commits] [mlir] [MLIR][LLVM] Query target extension type data layouts (PR #236540)
Akimasa Watanuki
llvmlistbot at llvm.org
Wed Oct 28 12:13:43 PDT 2026
https://github.com/Men-cotton created https://github.com/llvm/llvm-project/pull/236540
Expose the layout representation of LLVM target extension types and delegate size and alignment queries to that representation. Follow LLVM target type layout rules for pointer representations, explicit SPIR-V layouts, padding, and scalable vectors so clients do not need target-name-specific alignment fallbacks.
Assisted-by: Codex / GPT-6
>From c9b984ee2d2a7a2a61433c4bb8467820a595fae9 Mon Sep 17 00:00:00 2001
From: mencotton <mencotton0410 at gmail.com>
Date: Mon, 26 Oct 2026 11:10:57 -0500
Subject: [PATCH] [MLIR][LLVM] Query target extension type data layouts
Expose the layout representation of LLVM target extension types and delegate size and alignment queries to that representation. Follow LLVM target type layout rules for pointer representations, explicit SPIR-V layouts, padding, and scalable vectors so clients do not need target-name-specific alignment fallbacks.
Assisted-by: Codex / GPT-6
---
mlir/include/mlir/Dialect/LLVMIR/LLVMTypes.td | 7 +-
mlir/lib/Dialect/LLVMIR/IR/LLVMTypes.cpp | 69 +++++++++++++++
mlir/unittests/Dialect/LLVMIR/CMakeLists.txt | 1 +
.../unittests/Dialect/LLVMIR/LLVMTypeTest.cpp | 86 +++++++++++++++++++
4 files changed, 162 insertions(+), 1 deletion(-)
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMTypes.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMTypes.td
index e31323651ceda1..fb798789ab195e 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMTypes.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMTypes.td
@@ -330,7 +330,9 @@ def LLVMPointerType : LLVMType<"LLVMPointer", "ptr", [
// LLVMTargetExtType
//===----------------------------------------------------------------------===//
-def LLVMTargetExtType : LLVMType<"LLVMTargetExt", "target"> {
+def LLVMTargetExtType : LLVMType<"LLVMTargetExt", "target", [
+ DeclareTypeInterfaceMethods<DataLayoutTypeInterface,
+ ["getPreferredAlignment"]>]> {
let summary = "LLVM target-specific extension type";
let description = [{
LLVM dialect target extension type, which are generally unintrospectable
@@ -359,6 +361,9 @@ def LLVMTargetExtType : LLVMType<"LLVMTargetExt", "target"> {
bool hasProperty(Property Prop) const;
bool supportsMemOps() const;
+
+ /// Return the type used for layout, or void for an unsized extension type.
+ Type getLayoutType() const;
}];
}
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMTypes.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMTypes.cpp
index 2d99c0e4a4931d..0d7a9c31d86502 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMTypes.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMTypes.cpp
@@ -22,6 +22,7 @@
#include "llvm/ADT/TypeSwitch.h"
#include "llvm/Support/TypeSize.h"
+#include "llvm/TargetParser/RISCVTargetParser.h"
#include <optional>
using namespace mlir;
@@ -754,6 +755,74 @@ bool LLVM::LLVMTargetExtType::supportsMemOps() const {
return false;
}
+Type LLVM::LLVMTargetExtType::getLayoutType() const {
+ // Keep this mapping consistent with getTargetTypeInfo in
+ // llvm/lib/IR/Type.cpp.
+ MLIRContext *context = getContext();
+ StringRef name = getExtTypeName();
+ if (name == "spirv.Type") {
+ assert(getIntParams().size() == 3 &&
+ "wrong number of parameters for spirv.Type");
+ unsigned size = getIntParams()[1];
+ unsigned alignment = getIntParams()[2];
+ if (size && alignment)
+ return LLVMArrayType::get(IntegerType::get(context, alignment),
+ size * 8 / alignment);
+ return IntegerType::get(context, 32);
+ }
+ if (name == "spirv.IntegralConstant" || name == "spirv.Literal" ||
+ name == "amdgpu.stridemark")
+ return LLVMVoidType::get(context);
+ if (name == "spirv.Padding" || name == "dx.Padding") {
+ assert(getIntParams().size() == 1 && "expected padding size");
+ return LLVMArrayType::get(IntegerType::get(context, 8), getIntParams()[0]);
+ }
+ if (name.starts_with(kSpirvPrefix) || name.starts_with("dx.") ||
+ name == "wasm.funcref" || name == "wasm.externref")
+ return LLVMPointerType::get(context);
+ if (name == kArmSVCount)
+ return VectorType::get({16}, IntegerType::get(context, 1), {true});
+ if (name == "riscv.vector.tuple") {
+ assert(getTypeParams().size() == 1 && getIntParams().size() == 1 &&
+ "expected tuple vector type and field count");
+ unsigned numElements =
+ std::max(getVectorNumElements(getTypeParams()[0]).getKnownMinValue(),
+ llvm::RISCV::RVVBytesPerBlock) *
+ getIntParams()[0];
+ return VectorType::get({numElements}, IntegerType::get(context, 8), {true});
+ }
+ if (name == kAMDGCNNamedBarrier)
+ return IntegerType::get(context, 8);
+ if (name == "llvm.test.vectorelement")
+ return IntegerType::get(context, 32);
+ return LLVMVoidType::get(context);
+}
+
+llvm::TypeSize LLVM::LLVMTargetExtType::getTypeSizeInBits(
+ const DataLayout &dataLayout, DataLayoutEntryListRef params) const {
+ Type layoutType = getLayoutType();
+ // LLVM vector bit sizes do not round the element count up to a power of two,
+ // unlike the default data layout for builtin MLIR vectors.
+ if (auto vectorType = dyn_cast<VectorType>(layoutType))
+ return llvm::TypeSize::get(
+ vectorType.getNumElements() *
+ dataLayout.getTypeSizeInBits(vectorType.getElementType())
+ .getFixedValue(),
+ vectorType.isScalable());
+ return dataLayout.getTypeSizeInBits(layoutType);
+}
+
+uint64_t
+LLVM::LLVMTargetExtType::getABIAlignment(const DataLayout &dataLayout,
+ DataLayoutEntryListRef params) const {
+ return dataLayout.getTypeABIAlignment(getLayoutType());
+}
+
+uint64_t LLVM::LLVMTargetExtType::getPreferredAlignment(
+ const DataLayout &dataLayout, DataLayoutEntryListRef params) const {
+ return dataLayout.getTypePreferredAlignment(getLayoutType());
+}
+
//===----------------------------------------------------------------------===//
// LLVMPPCFP128Type
//===----------------------------------------------------------------------===//
diff --git a/mlir/unittests/Dialect/LLVMIR/CMakeLists.txt b/mlir/unittests/Dialect/LLVMIR/CMakeLists.txt
index 0dffa51bdcf167..784a857872658c 100644
--- a/mlir/unittests/Dialect/LLVMIR/CMakeLists.txt
+++ b/mlir/unittests/Dialect/LLVMIR/CMakeLists.txt
@@ -5,6 +5,7 @@ add_mlir_unittest(MLIRLLVMIRTests
)
mlir_target_link_libraries(MLIRLLVMIRTests
PRIVATE
+ MLIRDLTIDialect
MLIRFuncDialect
MLIRLLVMDialect
MLIRROCDLDialect
diff --git a/mlir/unittests/Dialect/LLVMIR/LLVMTypeTest.cpp b/mlir/unittests/Dialect/LLVMIR/LLVMTypeTest.cpp
index 72d8867d232aad..aa8176693f9a3e 100644
--- a/mlir/unittests/Dialect/LLVMIR/LLVMTypeTest.cpp
+++ b/mlir/unittests/Dialect/LLVMIR/LLVMTypeTest.cpp
@@ -7,7 +7,13 @@
//===----------------------------------------------------------------------===//
#include "LLVMTestBase.h"
+#include "mlir/Dialect/DLTI/DLTI.h"
#include "mlir/Dialect/LLVMIR/LLVMTypes.h"
+#include "mlir/IR/Builders.h"
+#include "mlir/IR/BuiltinOps.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/LLVMContext.h"
using namespace mlir;
using namespace mlir::LLVM;
@@ -60,3 +66,83 @@ TEST_F(LLVMIRTest, StructElementOffsets) {
EXPECT_EQ(packedAlloc.getElementOffset(dataLayout, 1), 16u);
EXPECT_EQ(dataLayout.getTypeSize(packedAlloc), 17u);
}
+
+TEST_F(LLVMIRTest, TargetExtensionLayoutMatchesLLVM) {
+ DataLayout layout;
+ llvm::LLVMContext llvmContext;
+ llvm::DataLayout llvmLayout("");
+ auto check = [&](StringRef name, ArrayRef<Type> typeParams,
+ ArrayRef<llvm::Type *> llvmTypeParams,
+ ArrayRef<unsigned> intParams) {
+ SCOPED_TRACE(name.str());
+ auto type = LLVMTargetExtType::get(&context, name, typeParams, intParams);
+ auto *llvmType =
+ llvm::TargetExtType::get(llvmContext, name, llvmTypeParams, intParams);
+ llvm::TypeSize size = layout.getTypeSizeInBits(type);
+ llvm::TypeSize llvmSize = llvmLayout.getTypeSizeInBits(llvmType);
+ EXPECT_EQ(size.getKnownMinValue(), llvmSize.getKnownMinValue());
+ EXPECT_EQ(size.isScalable(), llvmSize.isScalable());
+ EXPECT_EQ(layout.getTypeABIAlignment(type),
+ llvmLayout.getABITypeAlign(llvmType).value());
+ EXPECT_EQ(layout.getTypePreferredAlignment(type),
+ llvmLayout.getPrefTypeAlign(llvmType).value());
+ };
+
+ check("spirv.Image", {Float32Type::get(&context)},
+ {llvm::Type::getFloatTy(llvmContext)}, {1, 0, 0, 0, 0, 0, 0});
+ check("spirv.SignedImage", {}, {}, {});
+ check("spirv.Sampler", {}, {}, {});
+ check("spirv.Pipe", {}, {}, {0});
+ check("spirv.Event", {}, {}, {});
+ check("dx.RawBuffer", {IntegerType::get(&context, 32)},
+ {llvm::Type::getInt32Ty(llvmContext)}, {0, 0});
+ check("wasm.funcref", {}, {}, {});
+ check("wasm.externref", {}, {}, {});
+ check("spirv.Type", {}, {}, {0, 8, 32});
+ check("spirv.Type", {}, {}, {0, 0, 0});
+ check("spirv.Padding", {}, {}, {3});
+ check("dx.Padding", {}, {}, {3});
+ check("amdgcn.named.barrier", {}, {}, {0});
+ check("llvm.test.vectorelement", {}, {}, {});
+ check("aarch64.svcount", {}, {}, {});
+ check("riscv.vector.tuple",
+ {VectorType::get({4}, IntegerType::get(&context, 64), {true})},
+ {llvm::ScalableVectorType::get(llvm::Type::getInt64Ty(llvmContext), 4)},
+ {3});
+}
+
+TEST_F(LLVMIRTest, UnsizedTargetExtensionLayout) {
+ for (StringRef name : {"spirv.IntegralConstant", "spirv.Literal",
+ "amdgpu.stridemark", "unknown"}) {
+ SCOPED_TRACE(name.str());
+ auto type = LLVMTargetExtType::get(&context, name, {}, {});
+ EXPECT_TRUE(isa<LLVMVoidType>(type.getLayoutType()));
+ }
+}
+
+TEST_F(LLVMIRTest, TargetExtensionLayoutInAggregates) {
+ DataLayout layout;
+ auto sampler = LLVMTargetExtType::get(&context, "spirv.Sampler", {}, {});
+ auto array = LLVMArrayType::get(sampler, 3);
+ EXPECT_EQ(layout.getTypeSize(array).getFixedValue(), 24u);
+ EXPECT_EQ(layout.getTypeABIAlignment(array), 8u);
+ auto record = LLVMStructType::getLiteral(
+ &context, {IntegerType::get(&context, 8), sampler});
+ EXPECT_EQ(record.getElementOffset(layout, 1), 8u);
+ EXPECT_EQ(layout.getTypeSize(record).getFixedValue(), 16u);
+}
+
+TEST_F(LLVMIRTest, TargetExtensionCustomPointerLayout) {
+ context.getOrLoadDialect<DLTIDialect>();
+ Builder builder(&context);
+ OwningOpRef<ModuleOp> module = ModuleOp::create(builder.getUnknownLoc());
+ auto pointerEntry = DataLayoutEntryAttr::get(
+ LLVMPointerType::get(&context), builder.getI64VectorAttr({32, 32, 64}));
+ (*module)->setAttr(DLTIDialect::kDataLayoutAttrName,
+ DataLayoutSpecAttr::get(&context, {pointerEntry}));
+ DataLayout layout(module.get());
+ auto sampler = LLVMTargetExtType::get(&context, "spirv.Sampler", {}, {});
+ EXPECT_EQ(layout.getTypeSizeInBits(sampler).getFixedValue(), 32u);
+ EXPECT_EQ(layout.getTypeABIAlignment(sampler), 4u);
+ EXPECT_EQ(layout.getTypePreferredAlignment(sampler), 8u);
+}
More information about the Mlir-commits
mailing list