[mlir][llvm] Support pointer entries in data layout translation

This adds support for pointer DLTI entries in LLVMIR export, e.g.
```
// translated to: p0:32:64:128
#dlti.dl_entry<!llvm.ptr, dense<[32,64,128]> : vector<3xi32>>
// translated to: p1:32:32:32:64
#dlti.dl_entry<!llvm.ptr<1>, dense<[32,32,32,64]> : vector<4xi32>>
```

Reviewed By: ftynse

Differential Revision: https://reviews.llvm.org/D133434
This commit is contained in:
rkayaith 2022-09-07 12:42:52 -04:00
parent bc14ed7de0
commit aa00e3e6c1
4 changed files with 78 additions and 53 deletions

View File

@ -535,6 +535,15 @@ Type getScalableVectorType(Type elementType, unsigned numElements);
/// (aggregates such as struct) or types that don't have a size (such as void). /// (aggregates such as struct) or types that don't have a size (such as void).
llvm::TypeSize getPrimitiveTypeSizeInBits(Type type); llvm::TypeSize getPrimitiveTypeSizeInBits(Type type);
/// The positions of different values in the data layout entry for pointers.
enum class PtrDLEntryPos { Size = 0, Abi = 1, Preferred = 2, Index = 3 };
/// Returns the value that corresponds to named position `pos` from the
/// data layout entry `attr` assuming it's a dense integer elements attribute.
/// Returns `None` if `pos` is not present in the entry.
/// Currently only `PtrDLEntryPos::Index` is optional, and all other positions
/// may be assumed to be present.
Optional<unsigned> extractPointerSpecValue(Attribute attr, PtrDLEntryPos pos);
} // namespace LLVM } // namespace LLVM
} // namespace mlir } // namespace mlir

View File

@ -229,19 +229,16 @@ LLVMPointerType::verify(function_ref<InFlightDiagnostic()> emitError,
return success(); return success();
} }
namespace {
/// The positions of different 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 kDefaultPointerSizeBits = 64;
constexpr const static unsigned kDefaultPointerAlignment = 8; constexpr const static unsigned kDefaultPointerAlignment = 8;
/// Returns the value that corresponds to named position `pos` from the Optional<unsigned> mlir::LLVM::extractPointerSpecValue(Attribute attr,
/// attribute `attr` assuming it's a dense integer elements attribute. PtrDLEntryPos pos) {
static unsigned extractPointerSpecValue(Attribute attr, DLEntryPos pos) { auto spec = attr.cast<DenseIntElementsAttr>();
return attr.cast<DenseIntElementsAttr>() auto idx = static_cast<unsigned>(pos);
.getValues<unsigned>()[static_cast<unsigned>(pos)]; if (idx >= spec.size())
return None;
return spec.getValues<unsigned>()[idx];
} }
/// Returns the part of the data layout entry that corresponds to `pos` for the /// Returns the part of the data layout entry that corresponds to `pos` for the
@ -250,7 +247,7 @@ static unsigned extractPointerSpecValue(Attribute attr, DLEntryPos pos) {
/// do not provide a custom one, for other address spaces returns None. /// do not provide a custom one, for other address spaces returns None.
static Optional<unsigned> static Optional<unsigned>
getPointerDataLayoutEntry(DataLayoutEntryListRef params, LLVMPointerType type, getPointerDataLayoutEntry(DataLayoutEntryListRef params, LLVMPointerType type,
DLEntryPos pos) { PtrDLEntryPos pos) {
// First, look for the entry for the pointer in the current address space. // First, look for the entry for the pointer in the current address space.
Attribute currentEntry; Attribute currentEntry;
for (DataLayoutEntryInterface entry : params) { for (DataLayoutEntryInterface entry : params) {
@ -263,15 +260,15 @@ getPointerDataLayoutEntry(DataLayoutEntryListRef params, LLVMPointerType type,
} }
} }
if (currentEntry) { if (currentEntry) {
return extractPointerSpecValue(currentEntry, pos) / return *extractPointerSpecValue(currentEntry, pos) /
(pos == DLEntryPos::Size ? 1 : kBitsInByte); (pos == PtrDLEntryPos::Size ? 1 : kBitsInByte);
} }
// If not found, and this is the pointer to the default memory space, assume // If not found, and this is the pointer to the default memory space, assume
// 64-bit pointers. // 64-bit pointers.
if (type.getAddressSpace() == 0) { if (type.getAddressSpace() == 0) {
return pos == DLEntryPos::Size ? kDefaultPointerSizeBits return pos == PtrDLEntryPos::Size ? kDefaultPointerSizeBits
: kDefaultPointerAlignment; : kDefaultPointerAlignment;
} }
return llvm::None; return llvm::None;
@ -281,7 +278,7 @@ unsigned
LLVMPointerType::getTypeSizeInBits(const DataLayout &dataLayout, LLVMPointerType::getTypeSizeInBits(const DataLayout &dataLayout,
DataLayoutEntryListRef params) const { DataLayoutEntryListRef params) const {
if (Optional<unsigned> size = if (Optional<unsigned> size =
getPointerDataLayoutEntry(params, *this, DLEntryPos::Size)) getPointerDataLayoutEntry(params, *this, PtrDLEntryPos::Size))
return *size; return *size;
// For other memory spaces, use the size of the pointer to the default memory // For other memory spaces, use the size of the pointer to the default memory
@ -294,7 +291,7 @@ LLVMPointerType::getTypeSizeInBits(const DataLayout &dataLayout,
unsigned LLVMPointerType::getABIAlignment(const DataLayout &dataLayout, unsigned LLVMPointerType::getABIAlignment(const DataLayout &dataLayout,
DataLayoutEntryListRef params) const { DataLayoutEntryListRef params) const {
if (Optional<unsigned> alignment = if (Optional<unsigned> alignment =
getPointerDataLayoutEntry(params, *this, DLEntryPos::Abi)) getPointerDataLayoutEntry(params, *this, PtrDLEntryPos::Abi))
return *alignment; return *alignment;
if (isOpaque()) if (isOpaque())
@ -306,7 +303,7 @@ unsigned
LLVMPointerType::getPreferredAlignment(const DataLayout &dataLayout, LLVMPointerType::getPreferredAlignment(const DataLayout &dataLayout,
DataLayoutEntryListRef params) const { DataLayoutEntryListRef params) const {
if (Optional<unsigned> alignment = if (Optional<unsigned> alignment =
getPointerDataLayoutEntry(params, *this, DLEntryPos::Preferred)) getPointerDataLayoutEntry(params, *this, PtrDLEntryPos::Preferred))
return *alignment; return *alignment;
if (isOpaque()) if (isOpaque())
@ -339,13 +336,13 @@ bool LLVMPointerType::areCompatible(DataLayoutEntryListRef oldLayout,
}); });
} }
if (it != oldLayout.end()) { if (it != oldLayout.end()) {
size = extractPointerSpecValue(*it, DLEntryPos::Size); size = *extractPointerSpecValue(*it, PtrDLEntryPos::Size);
abi = extractPointerSpecValue(*it, DLEntryPos::Abi); abi = *extractPointerSpecValue(*it, PtrDLEntryPos::Abi);
} }
Attribute newSpec = newEntry.getValue().cast<DenseIntElementsAttr>(); Attribute newSpec = newEntry.getValue().cast<DenseIntElementsAttr>();
unsigned newSize = extractPointerSpecValue(newSpec, DLEntryPos::Size); unsigned newSize = *extractPointerSpecValue(newSpec, PtrDLEntryPos::Size);
unsigned newAbi = extractPointerSpecValue(newSpec, DLEntryPos::Abi); unsigned newAbi = *extractPointerSpecValue(newSpec, PtrDLEntryPos::Abi);
if (size != newSize || abi < newAbi || abi % newAbi != 0) if (size != newSize || abi < newAbi || abi % newAbi != 0)
return false; return false;
} }
@ -369,8 +366,8 @@ LogicalResult LLVMPointerType::verifyEntries(DataLayoutEntryListRef entries,
return emitError(loc) << "unexpected layout attribute for pointer to " return emitError(loc) << "unexpected layout attribute for pointer to "
<< key.getElementType(); << key.getElementType();
} }
if (extractPointerSpecValue(values, DLEntryPos::Abi) > if (extractPointerSpecValue(values, PtrDLEntryPos::Abi) >
extractPointerSpecValue(values, DLEntryPos::Preferred)) { extractPointerSpecValue(values, PtrDLEntryPos::Preferred)) {
return emitError(loc) << "preferred alignment is expected to be at least " return emitError(loc) << "preferred alignment is expected to be at least "
"as large as ABI alignment"; "as large as ABI alignment";
} }

View File

@ -52,8 +52,8 @@ using namespace mlir::LLVM::detail;
#include "mlir/Dialect/LLVMIR/LLVMConversionEnumsToLLVM.inc" #include "mlir/Dialect/LLVMIR/LLVMConversionEnumsToLLVM.inc"
/// Translates the given data layout spec attribute to the LLVM IR data layout. /// Translates the given data layout spec attribute to the LLVM IR data layout.
/// Only integer, float and endianness entries are currently supported. /// Only integer, float, pointer and endianness entries are currently supported.
FailureOr<llvm::DataLayout> static FailureOr<llvm::DataLayout>
translateDataLayout(DataLayoutSpecInterface attribute, translateDataLayout(DataLayoutSpecInterface attribute,
const DataLayout &dataLayout, const DataLayout &dataLayout,
Optional<Location> loc = llvm::None) { Optional<Location> loc = llvm::None) {
@ -80,8 +80,8 @@ translateDataLayout(DataLayoutSpecInterface attribute,
} }
// Go through the list of entries to check which types are explicitly // Go through the list of entries to check which types are explicitly
// specified in entries. Don't use the entries directly though but query the // specified in entries. Where possible, data layout queries are used instead
// data from the layout. // of directly inspecting the entries.
for (DataLayoutEntryInterface entry : attribute.getEntries()) { for (DataLayoutEntryInterface entry : attribute.getEntries()) {
auto type = entry.getKey().dyn_cast<Type>(); auto type = entry.getKey().dyn_cast<Type>();
if (!type) if (!type)
@ -89,32 +89,47 @@ translateDataLayout(DataLayoutSpecInterface attribute,
// Data layout for the index type is irrelevant at this point. // Data layout for the index type is irrelevant at this point.
if (type.isa<IndexType>()) if (type.isa<IndexType>())
continue; continue;
FailureOr<std::string> prefix = layoutStream << "-";
llvm::TypeSwitch<Type, FailureOr<std::string>>(type) LogicalResult result =
.Case<IntegerType>( llvm::TypeSwitch<Type, LogicalResult>(type)
[loc](IntegerType integerType) -> FailureOr<std::string> { .Case<IntegerType, Float16Type, Float32Type, Float64Type,
if (integerType.getSignedness() == IntegerType::Signless) Float80Type, Float128Type>([&](Type type) -> LogicalResult {
return std::string("i"); if (auto intType = type.dyn_cast<IntegerType>()) {
emitError(*loc) if (intType.getSignedness() != IntegerType::Signless)
<< "unsupported data layout for non-signless integer " return emitError(*loc)
<< integerType; << "unsupported data layout for non-signless integer "
return failure(); << intType;
}) layoutStream << "i";
.Case<Float16Type, Float32Type, Float64Type, Float80Type, } else {
Float128Type>([](Type) { return std::string("f"); }) layoutStream << "f";
.Default([loc](Type type) -> FailureOr<std::string> { }
emitError(*loc) << "unsupported type in data layout: " << type; unsigned size = dataLayout.getTypeSizeInBits(type);
return failure(); unsigned abi = dataLayout.getTypeABIAlignment(type) * 8u;
unsigned preferred =
dataLayout.getTypePreferredAlignment(type) * 8u;
layoutStream << size << ":" << abi;
if (abi != preferred)
layoutStream << ":" << preferred;
return success();
})
.Case([&](LLVMPointerType ptrType) {
layoutStream << "p" << ptrType.getAddressSpace() << ":";
unsigned size = dataLayout.getTypeSizeInBits(type);
unsigned abi = dataLayout.getTypeABIAlignment(type) * 8u;
unsigned preferred =
dataLayout.getTypePreferredAlignment(type) * 8u;
layoutStream << size << ":" << abi << ":" << preferred;
if (Optional<unsigned> index = extractPointerSpecValue(
entry.getValue(), PtrDLEntryPos::Index))
layoutStream << ":" << *index;
return success();
})
.Default([loc](Type type) {
return emitError(*loc)
<< "unsupported type in data layout: " << type;
}); });
if (failed(prefix)) if (failed(result))
return failure(); return failure();
unsigned size = dataLayout.getTypeSizeInBits(type);
unsigned abi = dataLayout.getTypeABIAlignment(type) * 8u;
unsigned preferred = dataLayout.getTypePreferredAlignment(type) * 8u;
layoutStream << "-" << *prefix << size << ":" << abi;
if (abi != preferred)
layoutStream << ":" << preferred;
} }
layoutStream.flush(); layoutStream.flush();
StringRef layoutSpec(llvmDataLayout); StringRef layoutSpec(llvmDataLayout);

View File

@ -4,11 +4,15 @@
// CHECK: E- // CHECK: E-
// CHECK: i64:64:128 // CHECK: i64:64:128
// CHECK: f80:128:256 // CHECK: f80:128:256
// CHECK: p0:32:64:128
// CHECK: p1:32:32:32:64
module attributes {dlti.dl_spec = #dlti.dl_spec< module attributes {dlti.dl_spec = #dlti.dl_spec<
#dlti.dl_entry<"dlti.endianness", "big">, #dlti.dl_entry<"dlti.endianness", "big">,
#dlti.dl_entry<index, 64>, #dlti.dl_entry<index, 64>,
#dlti.dl_entry<i64, dense<[64,128]> : vector<2xi32>>, #dlti.dl_entry<i64, dense<[64,128]> : vector<2xi32>>,
#dlti.dl_entry<f80, dense<[128,256]> : vector<2xi32>> #dlti.dl_entry<f80, dense<[128,256]> : vector<2xi32>>,
#dlti.dl_entry<!llvm.ptr, dense<[32,64,128]> : vector<3xi32>>,
#dlti.dl_entry<!llvm.ptr<1>, dense<[32,32,32,64]> : vector<4xi32>>
>} { >} {
llvm.func @foo() { llvm.func @foo() {
llvm.return llvm.return