Skip to content

Commit ea99870

Browse files
committed
[mlir] Add partial support for translating data layout
Add support for translating data layout specifications for integer and float types between MLIR and LLVM IR. This is a first step towards removing the string-based LLVM dialect data layout attribute on modules. The latter is still available and will remain so until the first-class MLIR modeling can fully replace it. Depends On D120739 Reviewed By: wsmoses Differential Revision: https://reviews.llvm.org/D120740
1 parent f64170a commit ea99870

File tree

8 files changed

+249
-2
lines changed

8 files changed

+249
-2
lines changed

mlir/include/mlir/Target/LLVMIR/Import.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,13 @@
2020

2121
// Forward-declare LLVM classes.
2222
namespace llvm {
23+
class DataLayout;
2324
class Module;
2425
} // namespace llvm
2526

2627
namespace mlir {
2728

28-
class DialectRegistry;
29+
class DataLayoutSpecInterface;
2930
class MLIRContext;
3031
class ModuleOp;
3132

@@ -37,6 +38,11 @@ OwningOpRef<ModuleOp>
3738
translateLLVMIRToModule(std::unique_ptr<llvm::Module> llvmModule,
3839
MLIRContext *context);
3940

41+
/// Translate the given LLVM data layout into an MLIR equivalent using the DLTI
42+
/// dialect.
43+
DataLayoutSpecInterface translateDataLayout(const llvm::DataLayout &dataLayout,
44+
MLIRContext *context);
45+
4046
} // namespace mlir
4147

4248
#endif // MLIR_TARGET_LLVMIR_IMPORT_H

mlir/lib/Target/LLVMIR/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ add_mlir_translation_library(MLIRTargetLLVMIRExport
2727
TransformUtils
2828

2929
LINK_LIBS PUBLIC
30+
MLIRDLTI
3031
MLIRLLVMIR
3132
MLIRLLVMIRTransforms
3233
MLIRTranslation
@@ -59,6 +60,7 @@ add_mlir_translation_library(MLIRTargetLLVMIRImport
5960
IRReader
6061

6162
LINK_LIBS PUBLIC
63+
MLIRDLTI
6264
MLIRLLVMIR
6365
MLIRTranslation
6466
)

mlir/lib/Target/LLVMIR/ConvertFromLLVMIR.cpp

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@
1212

1313
#include "mlir/Target/LLVMIR/Import.h"
1414

15+
#include "mlir/Dialect/DLTI/DLTI.h"
1516
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
1617
#include "mlir/IR/Builders.h"
1718
#include "mlir/IR/BuiltinOps.h"
1819
#include "mlir/IR/BuiltinTypes.h"
1920
#include "mlir/IR/MLIRContext.h"
21+
#include "mlir/Interfaces/DataLayoutInterfaces.h"
2022
#include "mlir/Target/LLVMIR/TypeFromLLVM.h"
2123
#include "mlir/Translation.h"
2224

@@ -47,6 +49,91 @@ static std::string diag(llvm::Value &v) {
4749
return os.str();
4850
}
4951

52+
/// Creates an attribute containing ABI and preferred alignment numbers parsed
53+
/// a string. The string may be either "abi:preferred" or just "abi". In the
54+
/// latter case, the prefrred alignment is considered equal to ABI alignment.
55+
static DenseIntElementsAttr parseDataLayoutAlignment(MLIRContext &ctx,
56+
StringRef spec) {
57+
auto i32 = IntegerType::get(&ctx, 32);
58+
59+
StringRef abiString, preferredString;
60+
std::tie(abiString, preferredString) = spec.split(':');
61+
int abi, preferred;
62+
if (abiString.getAsInteger(/*Radix=*/10, abi))
63+
return nullptr;
64+
65+
if (preferredString.empty())
66+
preferred = abi;
67+
else if (preferredString.getAsInteger(/*Radix=*/10, preferred))
68+
return nullptr;
69+
70+
return DenseIntElementsAttr::get(VectorType::get({2}, i32), {abi, preferred});
71+
}
72+
73+
/// Returns a supported MLIR floating point type of the given bit width or null
74+
/// if the bit width is not supported.
75+
static FloatType getDLFloatType(MLIRContext &ctx, int32_t bitwidth) {
76+
switch (bitwidth) {
77+
case 16:
78+
return FloatType::getF16(&ctx);
79+
case 32:
80+
return FloatType::getF32(&ctx);
81+
case 64:
82+
return FloatType::getF64(&ctx);
83+
case 80:
84+
return FloatType::getF80(&ctx);
85+
case 128:
86+
return FloatType::getF128(&ctx);
87+
default:
88+
return nullptr;
89+
}
90+
}
91+
92+
DataLayoutSpecInterface
93+
mlir::translateDataLayout(const llvm::DataLayout &dataLayout,
94+
MLIRContext *context) {
95+
assert(context && "expected MLIR context");
96+
StringRef layout = dataLayout.getStringRepresentation();
97+
SmallVector<DataLayoutEntryInterface> entries;
98+
while (!layout.empty()) {
99+
// Split at '-'.
100+
std::pair<StringRef, StringRef> split = layout.split('-');
101+
StringRef current;
102+
std::tie(current, layout) = split;
103+
104+
// Split at ':'.
105+
StringRef kind, spec;
106+
std::tie(kind, spec) = current.split(':');
107+
108+
char symbol = kind.front();
109+
StringRef parameter = kind.substr(1);
110+
111+
if (symbol == 'i' || symbol == 'f') {
112+
unsigned bitwidth;
113+
if (parameter.getAsInteger(/*Radix=*/10, bitwidth))
114+
return nullptr;
115+
DenseIntElementsAttr params = parseDataLayoutAlignment(*context, spec);
116+
if (!params)
117+
return nullptr;
118+
auto entry = DataLayoutEntryAttr::get(
119+
symbol == 'i' ? static_cast<Type>(IntegerType::get(context, bitwidth))
120+
: getDLFloatType(*context, bitwidth),
121+
params);
122+
entries.emplace_back(entry);
123+
} else if (symbol == 'e' || symbol == 'E') {
124+
auto value = StringAttr::get(
125+
context, symbol == 'e' ? DLTIDialect::kDataLayoutEndiannessLittle
126+
: DLTIDialect::kDataLayoutEndiannessBig);
127+
auto entry = DataLayoutEntryAttr::get(
128+
StringAttr::get(context, DLTIDialect::kDataLayoutEndiannessKey),
129+
value);
130+
entries.emplace_back(entry);
131+
}
132+
}
133+
134+
return DataLayoutSpecAttr::get(context, entries);
135+
}
136+
50137
// Handles importing globals and functions from an LLVM module.
51138
namespace {
52139
class Importer {
@@ -862,9 +949,19 @@ OwningOpRef<ModuleOp>
862949
mlir::translateLLVMIRToModule(std::unique_ptr<llvm::Module> llvmModule,
863950
MLIRContext *context) {
864951
context->loadDialect<LLVMDialect>();
952+
context->loadDialect<DLTIDialect>();
865953
OwningOpRef<ModuleOp> module(ModuleOp::create(
866954
FileLineColLoc::get(context, "", /*line=*/0, /*column=*/0)));
867955

956+
DataLayoutSpecInterface dlSpec =
957+
translateDataLayout(llvmModule->getDataLayout(), context);
958+
if (!dlSpec) {
959+
emitError(UnknownLoc::get(context), "can't translate data layout");
960+
return {};
961+
}
962+
963+
module.get()->setAttr(DLTIDialect::kDataLayoutAttrName, dlSpec);
964+
868965
Importer deserializer(context, module.get());
869966
for (llvm::GlobalVariable &gv : llvmModule->globals()) {
870967
if (!deserializer.processGlobal(&gv))

mlir/lib/Target/LLVMIR/ConvertToLLVMIR.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
#include "mlir/Dialect/DLTI/DLTI.h"
1314
#include "mlir/IR/BuiltinOps.h"
1415
#include "mlir/Target/LLVMIR/Dialect/All.h"
1516
#include "mlir/Target/LLVMIR/Export.h"
@@ -33,6 +34,7 @@ void registerToLLVMIRTranslation() {
3334
return success();
3435
},
3536
[](DialectRegistry &registry) {
37+
registry.insert<DLTIDialect>();
3638
registerAllToLLVMIRTranslations(registry);
3739
});
3840
}

mlir/lib/Target/LLVMIR/ModuleTranslation.cpp

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "mlir/Target/LLVMIR/ModuleTranslation.h"
1515

1616
#include "DebugTranslation.h"
17+
#include "mlir/Dialect/DLTI/DLTI.h"
1718
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
1819
#include "mlir/Dialect/LLVMIR/Transforms/LegalizeForExport.h"
1920
#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
@@ -50,6 +51,76 @@ using namespace mlir::LLVM::detail;
5051

5152
#include "mlir/Dialect/LLVMIR/LLVMConversionEnumsToLLVM.inc"
5253

54+
/// Translates the given data layout spec attribute to the LLVM IR data layout.
55+
/// Only integer, float and endianness entries are currently supported.
56+
FailureOr<llvm::DataLayout>
57+
translateDataLayout(DataLayoutSpecInterface attribute,
58+
const DataLayout &dataLayout,
59+
Optional<Location> loc = llvm::None) {
60+
if (!loc)
61+
loc = UnknownLoc::get(attribute.getContext());
62+
63+
// Translate the endianness attribute.
64+
std::string llvmDataLayout;
65+
llvm::raw_string_ostream layoutStream(llvmDataLayout);
66+
for (DataLayoutEntryInterface entry : attribute.getEntries()) {
67+
auto key = entry.getKey().dyn_cast<StringAttr>();
68+
if (!key)
69+
continue;
70+
if (key.getValue() == DLTIDialect::kDataLayoutEndiannessKey) {
71+
auto value = entry.getValue().cast<StringAttr>();
72+
bool isLittleEndian =
73+
value.getValue() == DLTIDialect::kDataLayoutEndiannessLittle;
74+
layoutStream << (isLittleEndian ? "e" : "E");
75+
layoutStream.flush();
76+
continue;
77+
}
78+
emitError(*loc) << "unsupported data layout key " << key;
79+
return failure();
80+
}
81+
82+
// Go through the list of entries to check which types are explicitly
83+
// specified in entries. Don't use the entries directly though but query the
84+
// data from the layout.
85+
for (DataLayoutEntryInterface entry : attribute.getEntries()) {
86+
auto type = entry.getKey().dyn_cast<Type>();
87+
if (!type)
88+
continue;
89+
FailureOr<std::string> prefix =
90+
llvm::TypeSwitch<Type, FailureOr<std::string>>(type)
91+
.Case<IntegerType>(
92+
[loc](IntegerType integerType) -> FailureOr<std::string> {
93+
if (integerType.getSignedness() == IntegerType::Signless)
94+
return std::string("i");
95+
emitError(*loc)
96+
<< "unsupported data layout for non-signless integer "
97+
<< integerType;
98+
return failure();
99+
})
100+
.Case<Float16Type, Float32Type, Float64Type, Float80Type,
101+
Float128Type>([](Type) { return std::string("f"); })
102+
.Default([loc](Type type) -> FailureOr<std::string> {
103+
emitError(*loc) << "unsupported type in data layout: " << type;
104+
return failure();
105+
});
106+
if (failed(prefix))
107+
return failure();
108+
109+
unsigned size = dataLayout.getTypeSizeInBits(type);
110+
unsigned abi = dataLayout.getTypeABIAlignment(type) * 8u;
111+
unsigned preferred = dataLayout.getTypePreferredAlignment(type) * 8u;
112+
layoutStream << "-" << *prefix << size << ":" << abi;
113+
if (abi != preferred)
114+
layoutStream << ":" << preferred;
115+
}
116+
layoutStream.flush();
117+
StringRef layoutSpec(llvmDataLayout);
118+
if (layoutSpec.startswith("-"))
119+
layoutSpec = layoutSpec.drop_front();
120+
121+
return llvm::DataLayout(layoutSpec);
122+
}
123+
53124
/// Builds a constant of a sequential LLVM type `type`, potentially containing
54125
/// other sequential types recursively, from the individual constant values
55126
/// provided in `constants`. `shape` contains the number of elements in nested
@@ -1010,8 +1081,25 @@ prepareLLVMModule(Operation *m, llvm::LLVMContext &llvmContext,
10101081
m->getContext()->getOrLoadDialect<LLVM::LLVMDialect>();
10111082
auto llvmModule = std::make_unique<llvm::Module>(name, llvmContext);
10121083
if (auto dataLayoutAttr =
1013-
m->getAttr(LLVM::LLVMDialect::getDataLayoutAttrName()))
1084+
m->getAttr(LLVM::LLVMDialect::getDataLayoutAttrName())) {
10141085
llvmModule->setDataLayout(dataLayoutAttr.cast<StringAttr>().getValue());
1086+
} else {
1087+
FailureOr<llvm::DataLayout> llvmDataLayout(llvm::DataLayout(""));
1088+
if (auto iface = dyn_cast<DataLayoutOpInterface>(m)) {
1089+
if (DataLayoutSpecInterface spec = iface.getDataLayoutSpec()) {
1090+
llvmDataLayout =
1091+
translateDataLayout(spec, DataLayout(iface), m->getLoc());
1092+
}
1093+
} else if (auto mod = dyn_cast<ModuleOp>(m)) {
1094+
if (DataLayoutSpecInterface spec = mod.getDataLayoutSpec()) {
1095+
llvmDataLayout =
1096+
translateDataLayout(spec, DataLayout(mod), m->getLoc());
1097+
}
1098+
}
1099+
if (failed(llvmDataLayout))
1100+
return nullptr;
1101+
llvmModule->setDataLayout(*llvmDataLayout);
1102+
}
10151103
if (auto targetTripleAttr =
10161104
m->getAttr(LLVM::LLVMDialect::getTargetTripleAttrName()))
10171105
llvmModule->setTargetTriple(targetTripleAttr.cast<StringAttr>().getValue());
@@ -1032,8 +1120,11 @@ mlir::translateModuleToLLVMIR(Operation *module, llvm::LLVMContext &llvmContext,
10321120
StringRef name) {
10331121
if (!satisfiesLLVMModule(module))
10341122
return nullptr;
1123+
10351124
std::unique_ptr<llvm::Module> llvmModule =
10361125
prepareLLVMModule(module, llvmContext, name);
1126+
if (!llvmModule)
1127+
return nullptr;
10371128

10381129
LLVM::ensureDistinctSuccessors(module);
10391130

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
; RUN: mlir-translate -import-llvm %s | FileCheck %s
2+
3+
; CHECK: dlti.dl_spec =
4+
; CHECK: #dlti.dl_spec<
5+
; CHECK: #dlti.dl_entry<"dlti.endianness", "little">
6+
; CHECK: #dlti.dl_entry<i64, dense<64> : vector<2xi32>>
7+
; CHECK: #dlti.dl_entry<f80, dense<128> : vector<2xi32>>
8+
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
9+
10+
declare void @foo()
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// RUN: mlir-translate -mlir-to-llvmir %s -split-input-file -verify-diagnostics | FileCheck %s
2+
3+
// CHECK: target datalayout
4+
// CHECK: E-
5+
// CHECK: i64:64:128
6+
// CHECK: f80:128:256
7+
module attributes {dlti.dl_spec = #dlti.dl_spec<
8+
#dlti.dl_entry<"dlti.endianness", "big">,
9+
#dlti.dl_entry<i64, dense<[64,128]> : vector<2xi32>>,
10+
#dlti.dl_entry<f80, dense<[128,256]> : vector<2xi32>>
11+
>} {
12+
llvm.func @foo() {
13+
llvm.return
14+
}
15+
}
16+
17+
// -----
18+
19+
// expected-error@below {{unsupported data layout for non-signless integer 'ui64'}}
20+
module attributes {dlti.dl_spec = #dlti.dl_spec<
21+
#dlti.dl_entry<ui64, dense<[64,128]> : vector<2xi32>>>
22+
} {}
23+
24+
// -----
25+
26+
// expected-error@below {{unsupported type in data layout: 'bf16'}}
27+
module attributes {dlti.dl_spec = #dlti.dl_spec<
28+
#dlti.dl_entry<bf16, dense<[64,128]> : vector<2xi32>>>
29+
} {}
30+
31+
// -----
32+
33+
// expected-error@below {{unsupported data layout key "foo"}}
34+
module attributes {dlti.dl_spec = #dlti.dl_spec<
35+
#dlti.dl_entry<"foo", dense<[64,128]> : vector<2xi32>>>
36+
} {}

utils/bazel/llvm-project-overlay/mlir/BUILD.bazel

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5542,6 +5542,7 @@ cc_library(
55425542
],
55435543
includes = ["include"],
55445544
deps = [
5545+
":DLTIDialect",
55455546
":IR",
55465547
":LLVMConversionIncGen",
55475548
":LLVMDialect",
@@ -5725,6 +5726,7 @@ cc_library(
57255726
includes = ["include"],
57265727
deps = [
57275728
":AllToLLVMIRTranslations",
5729+
":DLTIDialect",
57285730
":IR",
57295731
":ToLLVMIRTranslation",
57305732
":Translation",
@@ -5745,6 +5747,7 @@ cc_library(
57455747
],
57465748
includes = ["include"],
57475749
deps = [
5750+
":DLTIDialect",
57485751
":IR",
57495752
":LLVMConversionIncGen",
57505753
":LLVMDialect",

0 commit comments

Comments
 (0)