[Mlir-commits] [mlir] 7325aae - [mlir] make LLVMPointerType implement the data layout type interface
Alex Zinenko
llvmlistbot at llvm.org
Thu Jun 10 02:24:23 PDT 2021
Author: Alex Zinenko
Date: 2021-06-10T11:24:16+02:00
New Revision: 7325aaefa52a4bee91391cda2521006c31ab8010
URL: https://github.com/llvm/llvm-project/commit/7325aaefa52a4bee91391cda2521006c31ab8010
DIFF: https://github.com/llvm/llvm-project/commit/7325aaefa52a4bee91391cda2521006c31ab8010.diff
LOG: [mlir] make LLVMPointerType implement the data layout type interface
This brings us closer to replacing the LLVM data layout string with a
first-class layout modeling in MLIR.
Depends On D103945
Reviewed By: nicolasvasilache
Differential Revision: https://reviews.llvm.org/D103946
Added:
mlir/test/Dialect/LLVMIR/layout.mlir
Modified:
mlir/include/mlir/Dialect/LLVMIR/LLVMTypes.h
mlir/lib/Dialect/LLVMIR/CMakeLists.txt
mlir/lib/Dialect/LLVMIR/IR/LLVMTypes.cpp
Removed:
################################################################################
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMTypes.h b/mlir/include/mlir/Dialect/LLVMIR/LLVMTypes.h
index 4a1449db04e4d..bf10bd51b4fc7 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMTypes.h
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMTypes.h
@@ -15,6 +15,7 @@
#define MLIR_DIALECT_LLVMIR_LLVMTYPES_H_
#include "mlir/IR/Types.h"
+#include "mlir/Interfaces/DataLayoutInterfaces.h"
namespace llvm {
class ElementCount;
@@ -148,7 +149,8 @@ class LLVMFunctionType
/// object in memory. It is parameterized by the element type and the address
/// space.
class LLVMPointerType : public Type::TypeBase<LLVMPointerType, Type,
- detail::LLVMPointerTypeStorage> {
+ detail::LLVMPointerTypeStorage,
+ DataLayoutTypeInterface::Trait> {
public:
/// Inherit base constructors.
using Base::Base;
@@ -166,14 +168,27 @@ class LLVMPointerType : public Type::TypeBase<LLVMPointerType, Type,
unsigned addressSpace = 0);
/// Returns the pointed-to type.
- Type getElementType();
+ Type getElementType() const;
/// Returns the address space of the pointer.
- unsigned getAddressSpace();
+ unsigned getAddressSpace() const;
/// Verifies that the type about to be constructed is well-formed.
static LogicalResult verify(function_ref<InFlightDiagnostic()> emitError,
Type pointee, unsigned);
+
+ /// Hooks for DataLayoutTypeInterface. Should not be called directly. Obtain a
+ /// DataLayout instance and query it instead.
+ unsigned getTypeSizeInBits(const DataLayout &dataLayout,
+ DataLayoutEntryListRef params) const;
+ unsigned getABIAlignment(const DataLayout &dataLayout,
+ DataLayoutEntryListRef params) const;
+ unsigned getPreferredAlignment(const DataLayout &dataLayout,
+ DataLayoutEntryListRef params) const;
+ bool areCompatible(DataLayoutEntryListRef oldLayout,
+ DataLayoutEntryListRef newLayout) const;
+ LogicalResult verifyEntries(DataLayoutEntryListRef entries,
+ Location loc) const;
};
//===----------------------------------------------------------------------===//
diff --git a/mlir/lib/Dialect/LLVMIR/CMakeLists.txt b/mlir/lib/Dialect/LLVMIR/CMakeLists.txt
index b11bc7c6594d6..45650e1d01567 100644
--- a/mlir/lib/Dialect/LLVMIR/CMakeLists.txt
+++ b/mlir/lib/Dialect/LLVMIR/CMakeLists.txt
@@ -24,6 +24,7 @@ add_mlir_dialect_library(MLIRLLVMIR
LINK_LIBS PUBLIC
MLIRCallInterfaces
MLIRControlFlowInterfaces
+ MLIRDataLayoutInterfaces
MLIRIR
MLIRSideEffectInterfaces
MLIRSupport
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMTypes.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMTypes.cpp
index f2abe89b54bb8..fc4663db18f48 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMTypes.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMTypes.cpp
@@ -136,9 +136,11 @@ LLVMPointerType::getChecked(function_ref<InFlightDiagnostic()> emitError,
addressSpace);
}
-Type LLVMPointerType::getElementType() { return getImpl()->pointeeType; }
+Type LLVMPointerType::getElementType() const { return getImpl()->pointeeType; }
-unsigned LLVMPointerType::getAddressSpace() { return getImpl()->addressSpace; }
+unsigned LLVMPointerType::getAddressSpace() const {
+ return getImpl()->addressSpace;
+}
LogicalResult
LLVMPointerType::verify(function_ref<InFlightDiagnostic()> emitError,
@@ -148,6 +150,149 @@ LLVMPointerType::verify(function_ref<InFlightDiagnostic()> emitError,
return success();
}
+namespace {
+/// The positions of
diff erent values in the data layout entry.
+enum class DLEntryPos { Size = 0, Abi = 1, Preferred = 2, Address = 3 };
+} // namespace
+
+constexpr const static unsigned kDefaultPointerSizeBits = 64;
+constexpr const static unsigned kDefaultPointerAlignment = 8;
+constexpr const static unsigned kBitsInByte = 8;
+
+/// Returns the value that corresponds to named position `pos` from the
+/// attribute `attr` assuming it's a dense integer elements attribute.
+static unsigned extractPointerSpecValue(Attribute attr, DLEntryPos pos) {
+ return attr.cast<DenseIntElementsAttr>().getValue<unsigned>(
+ static_cast<unsigned>(pos));
+}
+
+/// Returns the part of the data layout entry that corresponds to `pos` for the
+/// given `type` by interpreting the list of entries `params`. For the pointer
+/// type in the default address space, returns the default value if the entries
+/// do not provide a custom one, for other address spaces returns None.
+static Optional<unsigned>
+getPointerDataLayoutEntry(DataLayoutEntryListRef params, LLVMPointerType type,
+ DLEntryPos pos) {
+ // First, look for the entry for the pointer in the current address space.
+ Attribute currentEntry;
+ for (DataLayoutEntryInterface entry : params) {
+ if (!entry.isTypeEntry())
+ continue;
+ if (entry.getKey().get<Type>().cast<LLVMPointerType>().getAddressSpace() ==
+ type.getAddressSpace()) {
+ currentEntry = entry.getValue();
+ break;
+ }
+ }
+ if (currentEntry) {
+ return extractPointerSpecValue(currentEntry, pos) /
+ (pos == DLEntryPos::Size ? 1 : kBitsInByte);
+ }
+
+ // If not found, and this is the pointer to the default memory space, assume
+ // 64-bit pointers.
+ if (type.getAddressSpace() == 0) {
+ return pos == DLEntryPos::Size ? kDefaultPointerSizeBits
+ : kDefaultPointerAlignment;
+ }
+
+ return llvm::None;
+}
+
+unsigned
+LLVMPointerType::getTypeSizeInBits(const DataLayout &dataLayout,
+ DataLayoutEntryListRef params) const {
+ if (Optional<unsigned> size =
+ getPointerDataLayoutEntry(params, *this, DLEntryPos::Size))
+ return *size;
+
+ // For other memory spaces, use the size of the pointer to the default memory
+ // space.
+ return dataLayout.getTypeSizeInBits(get(getElementType()));
+}
+
+unsigned LLVMPointerType::getABIAlignment(const DataLayout &dataLayout,
+ DataLayoutEntryListRef params) const {
+ if (Optional<unsigned> alignment =
+ getPointerDataLayoutEntry(params, *this, DLEntryPos::Abi))
+ return *alignment;
+
+ return dataLayout.getTypeABIAlignment(get(getElementType()));
+}
+
+unsigned
+LLVMPointerType::getPreferredAlignment(const DataLayout &dataLayout,
+ DataLayoutEntryListRef params) const {
+ if (Optional<unsigned> alignment =
+ getPointerDataLayoutEntry(params, *this, DLEntryPos::Preferred))
+ return *alignment;
+
+ return dataLayout.getTypePreferredAlignment(get(getElementType()));
+}
+
+bool LLVMPointerType::areCompatible(DataLayoutEntryListRef oldLayout,
+ DataLayoutEntryListRef newLayout) const {
+ for (DataLayoutEntryInterface newEntry : newLayout) {
+ if (!newEntry.isTypeEntry())
+ continue;
+ unsigned size = kDefaultPointerSizeBits;
+ unsigned abi = kDefaultPointerAlignment;
+ auto newType = newEntry.getKey().get<Type>().cast<LLVMPointerType>();
+ auto it = llvm::find_if(oldLayout, [&](DataLayoutEntryInterface entry) {
+ if (auto type = entry.getKey().dyn_cast<Type>()) {
+ return type.cast<LLVMPointerType>().getAddressSpace() ==
+ newType.getAddressSpace();
+ }
+ return false;
+ });
+ if (it == oldLayout.end()) {
+ llvm::find_if(oldLayout, [&](DataLayoutEntryInterface entry) {
+ if (auto type = entry.getKey().dyn_cast<Type>()) {
+ return type.cast<LLVMPointerType>().getAddressSpace() == 0;
+ }
+ return false;
+ });
+ }
+ if (it != oldLayout.end()) {
+ size = extractPointerSpecValue(*it, DLEntryPos::Size);
+ abi = extractPointerSpecValue(*it, DLEntryPos::Abi);
+ }
+
+ Attribute newSpec = newEntry.getValue().cast<DenseIntElementsAttr>();
+ unsigned newSize = extractPointerSpecValue(newSpec, DLEntryPos::Size);
+ unsigned newAbi = extractPointerSpecValue(newSpec, DLEntryPos::Abi);
+ if (size != newSize || abi < newAbi || abi % newAbi != 0)
+ return false;
+ }
+ return true;
+}
+
+LogicalResult LLVMPointerType::verifyEntries(DataLayoutEntryListRef entries,
+ Location loc) const {
+ for (DataLayoutEntryInterface entry : entries) {
+ if (!entry.isTypeEntry())
+ continue;
+ auto key = entry.getKey().get<Type>().cast<LLVMPointerType>();
+ auto values = entry.getValue().dyn_cast<DenseIntElementsAttr>();
+ if (!values || (values.size() != 3 && values.size() != 4)) {
+ return emitError(loc)
+ << "expected layout attribute for " << entry.getKey().get<Type>()
+ << " to be a dense integer elements attribute with 3 or 4 "
+ "elements";
+ }
+ if (!key.getElementType().isInteger(8)) {
+ return emitError(loc) << "unexpected layout attribute for pointer to "
+ << key.getElementType();
+ }
+ if (extractPointerSpecValue(values, DLEntryPos::Abi) >
+ extractPointerSpecValue(values, DLEntryPos::Preferred)) {
+ return emitError(loc) << "preferred alignment is expected to be at least "
+ "as large as ABI alignment";
+ }
+ }
+ return success();
+}
+
//===----------------------------------------------------------------------===//
// Struct type.
//===----------------------------------------------------------------------===//
diff --git a/mlir/test/Dialect/LLVMIR/layout.mlir b/mlir/test/Dialect/LLVMIR/layout.mlir
new file mode 100644
index 0000000000000..245fee0cd2863
--- /dev/null
+++ b/mlir/test/Dialect/LLVMIR/layout.mlir
@@ -0,0 +1,113 @@
+// RUN: mlir-opt --test-data-layout-query --split-input-file --verify-diagnostics %s | FileCheck %s
+
+module {
+ // CHECK: @no_spec
+ func @no_spec() {
+ // CHECK: alignment = 8
+ // CHECK: bitsize = 64
+ // CHECK: preferred = 8
+ // CHECK: size = 8
+ "test.data_layout_query"() : () -> !llvm.ptr<i8>
+ // CHECK: alignment = 8
+ // CHECK: bitsize = 64
+ // CHECK: preferred = 8
+ // CHECK: size = 8
+ "test.data_layout_query"() : () -> !llvm.ptr<i32>
+ // CHECK: alignment = 8
+ // CHECK: bitsize = 64
+ // CHECK: preferred = 8
+ // CHECK: size = 8
+ "test.data_layout_query"() : () -> !llvm.ptr<bf16>
+ // CHECK: alignment = 8
+ // CHECK: bitsize = 64
+ // CHECK: preferred = 8
+ // CHECK: size = 8
+ "test.data_layout_query"() : () -> !llvm.ptr<!llvm.ptr<i8>>
+ // CHECK: alignment = 8
+ // CHECK: bitsize = 64
+ // CHECK: preferred = 8
+ // CHECK: size = 8
+ "test.data_layout_query"() : () -> !llvm.ptr<i8, 3>
+ // CHECK: alignment = 8
+ // CHECK: bitsize = 64
+ // CHECK: preferred = 8
+ // CHECK: size = 8
+ "test.data_layout_query"() : () -> !llvm.ptr<i8, 5>
+ return
+ }
+}
+
+// -----
+
+module attributes { dlti.dl_spec = #dlti.dl_spec<
+ #dlti.dl_entry<!llvm.ptr<i8>, dense<[32, 32, 64]> : vector<3xi32>>,
+ #dlti.dl_entry<!llvm.ptr<i8, 5>, dense<[64, 64, 64]> : vector<3xi32>>
+>} {
+ // CHECK: @spec
+ func @spec() {
+ // CHECK: alignment = 4
+ // CHECK: bitsize = 32
+ // CHECK: preferred = 8
+ // CHECK: size = 4
+ "test.data_layout_query"() : () -> !llvm.ptr<i8>
+ // CHECK: alignment = 4
+ // CHECK: bitsize = 32
+ // CHECK: preferred = 8
+ // CHECK: size = 4
+ "test.data_layout_query"() : () -> !llvm.ptr<i32>
+ // CHECK: alignment = 4
+ // CHECK: bitsize = 32
+ // CHECK: preferred = 8
+ // CHECK: size = 4
+ "test.data_layout_query"() : () -> !llvm.ptr<bf16>
+ // CHECK: alignment = 4
+ // CHECK: bitsize = 32
+ // CHECK: preferred = 8
+ // CHECK: size = 4
+ "test.data_layout_query"() : () -> !llvm.ptr<!llvm.ptr<i8>>
+ // CHECK: alignment = 4
+ // CHECK: bitsize = 32
+ // CHECK: preferred = 8
+ // CHECK: size = 4
+ "test.data_layout_query"() : () -> !llvm.ptr<i8, 3>
+ // CHECK: alignment = 8
+ // CHECK: bitsize = 64
+ // CHECK: preferred = 8
+ // CHECK: size = 8
+ "test.data_layout_query"() : () -> !llvm.ptr<i8, 5>
+ return
+ }
+}
+
+// -----
+
+// expected-error at below {{unexpected layout attribute for pointer to 'i32'}}
+module attributes { dlti.dl_spec = #dlti.dl_spec<
+ #dlti.dl_entry<!llvm.ptr<i32>, dense<[64, 64, 64]> : vector<3xi32>>
+>} {
+ func @pointer() {
+ return
+ }
+}
+
+// -----
+
+// expected-error at below {{expected layout attribute for '!llvm.ptr<i8>' to be a dense integer elements attribute with 3 or 4 elements}}
+module attributes { dlti.dl_spec = #dlti.dl_spec<
+ #dlti.dl_entry<!llvm.ptr<i8>, dense<[64.0, 64.0, 64.0]> : vector<3xf32>>
+>} {
+ func @pointer() {
+ return
+ }
+}
+
+// -----
+
+// expected-error at below {{preferred alignment is expected to be at least as large as ABI alignment}}
+module attributes { dlti.dl_spec = #dlti.dl_spec<
+ #dlti.dl_entry<!llvm.ptr<i8>, dense<[64, 64, 32]> : vector<3xi32>>
+>} {
+ func @pointer() {
+ return
+ }
+}
More information about the Mlir-commits
mailing list