forked from OSchip/llvm-project
[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:
parent
bc14ed7de0
commit
aa00e3e6c1
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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";
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue