1 //===- DataLayoutImporter.cpp - LLVM to MLIR data layout conversion -------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "DataLayoutImporter.h"
10 #include "mlir/Dialect/DLTI/DLTI.h"
11 #include "mlir/Dialect/LLVMIR/LLVMDialect.h"
12 #include "mlir/IR/Builders.h"
13 #include "mlir/IR/BuiltinAttributes.h"
14 #include "mlir/IR/BuiltinTypes.h"
15 #include "mlir/Interfaces/DataLayoutInterfaces.h"
16 #include "mlir/Target/LLVMIR/Import.h"
17 #include "llvm/IR/DataLayout.h"
20 using namespace mlir::LLVM
;
21 using namespace mlir::LLVM::detail
;
23 /// The default data layout used during the translation.
24 static constexpr StringRef kDefaultDataLayout
=
25 "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-"
26 "f16:16:16-f64:64:64-f128:128:128";
28 FloatType
mlir::LLVM::detail::getFloatType(MLIRContext
*context
,
32 return FloatType::getF16(context
);
34 return FloatType::getF32(context
);
36 return FloatType::getF64(context
);
38 return FloatType::getF80(context
);
40 return FloatType::getF128(context
);
47 DataLayoutImporter::tryToParseAlphaPrefix(StringRef
&token
) const {
51 StringRef prefix
= token
.take_while(isalpha
);
55 token
.consume_front(prefix
);
59 FailureOr
<uint64_t> DataLayoutImporter::tryToParseInt(StringRef
&token
) const {
61 if (token
.consumeInteger(/*Radix=*/10, parameter
))
66 FailureOr
<SmallVector
<uint64_t>>
67 DataLayoutImporter::tryToParseIntList(StringRef token
) const {
68 SmallVector
<StringRef
> tokens
;
69 token
.consume_front(":");
70 token
.split(tokens
, ':');
72 // Parse an integer list.
73 SmallVector
<uint64_t> results(tokens
.size());
74 for (auto [result
, token
] : llvm::zip(results
, tokens
))
75 if (token
.getAsInteger(/*Radix=*/10, result
))
80 FailureOr
<DenseIntElementsAttr
>
81 DataLayoutImporter::tryToParseAlignment(StringRef token
) const {
82 FailureOr
<SmallVector
<uint64_t>> alignment
= tryToParseIntList(token
);
83 if (failed(alignment
))
85 if (alignment
->empty() || alignment
->size() > 2)
88 // Alignment specifications (such as 32 or 32:64) are of the
89 // form <abi>[:<pref>], where abi specifies the minimal alignment and pref the
90 // optional preferred alignment. The preferred alignment is set to the minimal
91 // alignment if not available.
92 uint64_t minimal
= (*alignment
)[0];
93 uint64_t preferred
= alignment
->size() == 1 ? minimal
: (*alignment
)[1];
94 return DenseIntElementsAttr::get(
95 VectorType::get({2}, IntegerType::get(context
, 64)),
96 {minimal
, preferred
});
99 FailureOr
<DenseIntElementsAttr
>
100 DataLayoutImporter::tryToParsePointerAlignment(StringRef token
) const {
101 FailureOr
<SmallVector
<uint64_t>> alignment
= tryToParseIntList(token
);
102 if (failed(alignment
))
104 if (alignment
->size() < 2 || alignment
->size() > 4)
107 // Pointer alignment specifications (such as 64:32:64:32 or 32:32) are of
108 // the form <size>:<abi>[:<pref>][:<idx>], where size is the pointer size, abi
109 // specifies the minimal alignment, pref the optional preferred alignment, and
110 // idx the optional index computation bit width. The preferred alignment is
111 // set to the minimal alignment if not available and the index computation
112 // width is set to the pointer size if not available.
113 uint64_t size
= (*alignment
)[0];
114 uint64_t minimal
= (*alignment
)[1];
115 uint64_t preferred
= alignment
->size() < 3 ? minimal
: (*alignment
)[2];
116 uint64_t idx
= alignment
->size() < 4 ? size
: (*alignment
)[3];
117 return DenseIntElementsAttr::get
<uint64_t>(
118 VectorType::get({4}, IntegerType::get(context
, 64)),
119 {size
, minimal
, preferred
, idx
});
122 LogicalResult
DataLayoutImporter::tryToEmplaceAlignmentEntry(Type type
,
124 auto key
= TypeAttr::get(type
);
125 if (typeEntries
.count(key
))
128 FailureOr
<DenseIntElementsAttr
> params
= tryToParseAlignment(token
);
132 typeEntries
.try_emplace(key
, DataLayoutEntryAttr::get(type
, *params
));
137 DataLayoutImporter::tryToEmplacePointerAlignmentEntry(LLVMPointerType type
,
139 auto key
= TypeAttr::get(type
);
140 if (typeEntries
.count(key
))
143 FailureOr
<DenseIntElementsAttr
> params
= tryToParsePointerAlignment(token
);
147 typeEntries
.try_emplace(key
, DataLayoutEntryAttr::get(type
, *params
));
152 DataLayoutImporter::tryToEmplaceEndiannessEntry(StringRef endianness
,
154 auto key
= StringAttr::get(context
, DLTIDialect::kDataLayoutEndiannessKey
);
155 if (keyEntries
.count(key
))
161 keyEntries
.try_emplace(
162 key
, DataLayoutEntryAttr::get(key
, StringAttr::get(context
, endianness
)));
167 DataLayoutImporter::tryToEmplaceAddrSpaceEntry(StringRef token
,
168 llvm::StringLiteral spaceKey
) {
169 auto key
= StringAttr::get(context
, spaceKey
);
170 if (keyEntries
.count(key
))
173 FailureOr
<uint64_t> space
= tryToParseInt(token
);
177 // Only store the address space if it has a non-default value.
180 OpBuilder
builder(context
);
181 keyEntries
.try_emplace(
183 DataLayoutEntryAttr::get(
184 key
, builder
.getIntegerAttr(
185 builder
.getIntegerType(64, /*isSigned=*/false), *space
)));
190 DataLayoutImporter::tryToEmplaceStackAlignmentEntry(StringRef token
) {
192 StringAttr::get(context
, DLTIDialect::kDataLayoutStackAlignmentKey
);
193 if (keyEntries
.count(key
))
196 FailureOr
<uint64_t> alignment
= tryToParseInt(token
);
197 if (failed(alignment
))
200 // Stack alignment shouldn't be zero.
203 OpBuilder
builder(context
);
204 keyEntries
.try_emplace(key
, DataLayoutEntryAttr::get(
205 key
, builder
.getI64IntegerAttr(*alignment
)));
209 void DataLayoutImporter::translateDataLayout(
210 const llvm::DataLayout
&llvmDataLayout
) {
213 // Transform the data layout to its string representation and append the
214 // default data layout string specified in the language reference
215 // (https://llvm.org/docs/LangRef.html#data-layout). The translation then
216 // parses the string and ignores the default value if a specific kind occurs
217 // in both strings. Additionally, the following default values exist:
218 // - non-default address space pointer specifications default to the default
219 // address space pointer specification
220 // - the alloca address space defaults to the default address space.
221 layoutStr
= llvmDataLayout
.getStringRepresentation();
222 if (!layoutStr
.empty())
224 layoutStr
+= kDefaultDataLayout
;
225 StringRef
layout(layoutStr
);
227 // Split the data layout string into tokens separated by a dash.
228 SmallVector
<StringRef
> tokens
;
229 layout
.split(tokens
, '-');
231 for (StringRef token
: tokens
) {
233 FailureOr
<StringRef
> prefix
= tryToParseAlphaPrefix(token
);
237 // Parse the endianness.
238 if (*prefix
== "e") {
239 if (failed(tryToEmplaceEndiannessEntry(
240 DLTIDialect::kDataLayoutEndiannessLittle
, token
)))
244 if (*prefix
== "E") {
245 if (failed(tryToEmplaceEndiannessEntry(
246 DLTIDialect::kDataLayoutEndiannessBig
, token
)))
250 // Parse the program address space.
251 if (*prefix
== "P") {
252 if (failed(tryToEmplaceAddrSpaceEntry(
253 token
, DLTIDialect::kDataLayoutProgramMemorySpaceKey
)))
257 // Parse the global address space.
258 if (*prefix
== "G") {
259 if (failed(tryToEmplaceAddrSpaceEntry(
260 token
, DLTIDialect::kDataLayoutGlobalMemorySpaceKey
)))
264 // Parse the alloca address space.
265 if (*prefix
== "A") {
266 if (failed(tryToEmplaceAddrSpaceEntry(
267 token
, DLTIDialect::kDataLayoutAllocaMemorySpaceKey
)))
271 // Parse the stack alignment.
272 if (*prefix
== "S") {
273 if (failed(tryToEmplaceStackAlignmentEntry(token
)))
277 // Parse integer alignment specifications.
278 if (*prefix
== "i") {
279 FailureOr
<uint64_t> width
= tryToParseInt(token
);
283 Type type
= IntegerType::get(context
, *width
);
284 if (failed(tryToEmplaceAlignmentEntry(type
, token
)))
288 // Parse float alignment specifications.
289 if (*prefix
== "f") {
290 FailureOr
<uint64_t> width
= tryToParseInt(token
);
294 Type type
= getFloatType(context
, *width
);
295 if (failed(tryToEmplaceAlignmentEntry(type
, token
)))
299 // Parse pointer alignment specifications.
300 if (*prefix
== "p") {
301 FailureOr
<uint64_t> space
=
302 token
.starts_with(":") ? 0 : tryToParseInt(token
);
306 auto type
= LLVMPointerType::get(context
, *space
);
307 if (failed(tryToEmplacePointerAlignmentEntry(type
, token
)))
312 // Store all tokens that have not been handled.
313 unhandledTokens
.push_back(lastToken
);
316 // Assemble all entries to a data layout specification.
317 SmallVector
<DataLayoutEntryInterface
> entries
;
318 entries
.reserve(typeEntries
.size() + keyEntries
.size());
319 for (const auto &it
: typeEntries
)
320 entries
.push_back(it
.second
);
321 for (const auto &it
: keyEntries
)
322 entries
.push_back(it
.second
);
323 dataLayout
= DataLayoutSpecAttr::get(context
, entries
);
326 DataLayoutSpecInterface
327 mlir::translateDataLayout(const llvm::DataLayout
&dataLayout
,
328 MLIRContext
*context
) {
329 return DataLayoutImporter(context
, dataLayout
).getDataLayout();