#include "DataLayoutImporter.h"
#include "mlir/Dialect/DLTI/DLTI.h"
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinAttributes.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/Interfaces/DataLayoutInterfaces.h"
#include "mlir/Target/LLVMIR/Import.h"
#include "llvm/IR/DataLayout.h"
using namespace mlir;
using namespace mlir::LLVM;
using namespace mlir::LLVM::detail;
static constexpr StringRef kDefaultDataLayout =
"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-"
"f16:16:16-f64:64:64-f128:128:128";
FloatType mlir::LLVM::detail::getFloatType(MLIRContext *context,
unsigned width) {
switch (width) {
case 16:
return FloatType::getF16(context);
case 32:
return FloatType::getF32(context);
case 64:
return FloatType::getF64(context);
case 80:
return FloatType::getF80(context);
case 128:
return FloatType::getF128(context);
default:
return {};
}
}
FailureOr<StringRef>
DataLayoutImporter::tryToParseAlphaPrefix(StringRef &token) const {
if (token.empty())
return failure();
StringRef prefix = token.take_while(isalpha);
if (prefix.empty())
return failure();
token.consume_front(prefix);
return prefix;
}
FailureOr<uint64_t> DataLayoutImporter::tryToParseInt(StringRef &token) const {
uint64_t parameter;
if (token.consumeInteger(10, parameter))
return failure();
return parameter;
}
FailureOr<SmallVector<uint64_t>>
DataLayoutImporter::tryToParseIntList(StringRef token) const {
SmallVector<StringRef> tokens;
token.consume_front(":");
token.split(tokens, ':');
SmallVector<uint64_t> results(tokens.size());
for (auto [result, token] : llvm::zip(results, tokens))
if (token.getAsInteger(10, result))
return failure();
return results;
}
FailureOr<DenseIntElementsAttr>
DataLayoutImporter::tryToParseAlignment(StringRef token) const {
FailureOr<SmallVector<uint64_t>> alignment = tryToParseIntList(token);
if (failed(alignment))
return failure();
if (alignment->empty() || alignment->size() > 2)
return failure();
uint64_t minimal = (*alignment)[0];
uint64_t preferred = alignment->size() == 1 ? minimal : (*alignment)[1];
return DenseIntElementsAttr::get(
VectorType::get({2}, IntegerType::get(context, 64)),
{minimal, preferred});
}
FailureOr<DenseIntElementsAttr>
DataLayoutImporter::tryToParsePointerAlignment(StringRef token) const {
FailureOr<SmallVector<uint64_t>> alignment = tryToParseIntList(token);
if (failed(alignment))
return failure();
if (alignment->size() < 2 || alignment->size() > 4)
return failure();
uint64_t size = (*alignment)[0];
uint64_t minimal = (*alignment)[1];
uint64_t preferred = alignment->size() < 3 ? minimal : (*alignment)[2];
uint64_t idx = alignment->size() < 4 ? size : (*alignment)[3];
return DenseIntElementsAttr::get<uint64_t>(
VectorType::get({4}, IntegerType::get(context, 64)),
{size, minimal, preferred, idx});
}
LogicalResult DataLayoutImporter::tryToEmplaceAlignmentEntry(Type type,
StringRef token) {
auto key = TypeAttr::get(type);
if (typeEntries.count(key))
return success();
FailureOr<DenseIntElementsAttr> params = tryToParseAlignment(token);
if (failed(params))
return failure();
typeEntries.try_emplace(key, DataLayoutEntryAttr::get(type, *params));
return success();
}
LogicalResult
DataLayoutImporter::tryToEmplacePointerAlignmentEntry(LLVMPointerType type,
StringRef token) {
auto key = TypeAttr::get(type);
if (typeEntries.count(key))
return success();
FailureOr<DenseIntElementsAttr> params = tryToParsePointerAlignment(token);
if (failed(params))
return failure();
typeEntries.try_emplace(key, DataLayoutEntryAttr::get(type, *params));
return success();
}
LogicalResult
DataLayoutImporter::tryToEmplaceEndiannessEntry(StringRef endianness,
StringRef token) {
auto key = StringAttr::get(context, DLTIDialect::kDataLayoutEndiannessKey);
if (keyEntries.count(key))
return success();
if (!token.empty())
return failure();
keyEntries.try_emplace(
key, DataLayoutEntryAttr::get(key, StringAttr::get(context, endianness)));
return success();
}
LogicalResult
DataLayoutImporter::tryToEmplaceAddrSpaceEntry(StringRef token,
llvm::StringLiteral spaceKey) {
auto key = StringAttr::get(context, spaceKey);
if (keyEntries.count(key))
return success();
FailureOr<uint64_t> space = tryToParseInt(token);
if (failed(space))
return failure();
if (*space == 0)
return success();
OpBuilder builder(context);
keyEntries.try_emplace(
key,
DataLayoutEntryAttr::get(
key, builder.getIntegerAttr(
builder.getIntegerType(64, false), *space)));
return success();
}
LogicalResult
DataLayoutImporter::tryToEmplaceStackAlignmentEntry(StringRef token) {
auto key =
StringAttr::get(context, DLTIDialect::kDataLayoutStackAlignmentKey);
if (keyEntries.count(key))
return success();
FailureOr<uint64_t> alignment = tryToParseInt(token);
if (failed(alignment))
return failure();
if (*alignment == 0)
return success();
OpBuilder builder(context);
keyEntries.try_emplace(key, DataLayoutEntryAttr::get(
key, builder.getI64IntegerAttr(*alignment)));
return success();
}
void DataLayoutImporter::translateDataLayout(
const llvm::DataLayout &llvmDataLayout) {
dataLayout = {};
layoutStr = llvmDataLayout.getStringRepresentation();
if (!layoutStr.empty())
layoutStr += "-";
layoutStr += kDefaultDataLayout;
StringRef layout(layoutStr);
SmallVector<StringRef> tokens;
layout.split(tokens, '-');
for (StringRef token : tokens) {
lastToken = token;
FailureOr<StringRef> prefix = tryToParseAlphaPrefix(token);
if (failed(prefix))
return;
if (*prefix == "e") {
if (failed(tryToEmplaceEndiannessEntry(
DLTIDialect::kDataLayoutEndiannessLittle, token)))
return;
continue;
}
if (*prefix == "E") {
if (failed(tryToEmplaceEndiannessEntry(
DLTIDialect::kDataLayoutEndiannessBig, token)))
return;
continue;
}
if (*prefix == "P") {
if (failed(tryToEmplaceAddrSpaceEntry(
token, DLTIDialect::kDataLayoutProgramMemorySpaceKey)))
return;
continue;
}
if (*prefix == "G") {
if (failed(tryToEmplaceAddrSpaceEntry(
token, DLTIDialect::kDataLayoutGlobalMemorySpaceKey)))
return;
continue;
}
if (*prefix == "A") {
if (failed(tryToEmplaceAddrSpaceEntry(
token, DLTIDialect::kDataLayoutAllocaMemorySpaceKey)))
return;
continue;
}
if (*prefix == "S") {
if (failed(tryToEmplaceStackAlignmentEntry(token)))
return;
continue;
}
if (*prefix == "i") {
FailureOr<uint64_t> width = tryToParseInt(token);
if (failed(width))
return;
Type type = IntegerType::get(context, *width);
if (failed(tryToEmplaceAlignmentEntry(type, token)))
return;
continue;
}
if (*prefix == "f") {
FailureOr<uint64_t> width = tryToParseInt(token);
if (failed(width))
return;
Type type = getFloatType(context, *width);
if (failed(tryToEmplaceAlignmentEntry(type, token)))
return;
continue;
}
if (*prefix == "p") {
FailureOr<uint64_t> space =
token.starts_with(":") ? 0 : tryToParseInt(token);
if (failed(space))
return;
auto type = LLVMPointerType::get(context, *space);
if (failed(tryToEmplacePointerAlignmentEntry(type, token)))
return;
continue;
}
unhandledTokens.push_back(lastToken);
}
SmallVector<DataLayoutEntryInterface> entries;
entries.reserve(typeEntries.size() + keyEntries.size());
for (const auto &it : typeEntries)
entries.push_back(it.second);
for (const auto &it : keyEntries)
entries.push_back(it.second);
dataLayout = DataLayoutSpecAttr::get(context, entries);
}
DataLayoutSpecInterface
mlir::translateDataLayout(const llvm::DataLayout &dataLayout,
MLIRContext *context) {
return DataLayoutImporter(context, dataLayout).getDataLayout();
}