[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