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
<unsigned> DataLayoutImporter::tryToParseInt(StringRef
&token
) const {
61 if (token
.consumeInteger(/*Radix=*/10, parameter
))
66 FailureOr
<SmallVector
<unsigned>>
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
<unsigned> 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
<unsigned>> 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 unsigned minimal
= (*alignment
)[0];
93 unsigned preferred
= alignment
->size() == 1 ? minimal
: (*alignment
)[1];
94 return DenseIntElementsAttr::get(
95 VectorType::get({2}, IntegerType::get(context
, 32)),
96 {minimal
, preferred
});
99 FailureOr
<DenseIntElementsAttr
>
100 DataLayoutImporter::tryToParsePointerAlignment(StringRef token
) const {
101 FailureOr
<SmallVector
<unsigned>> 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 unsigned size
= (*alignment
)[0];
114 unsigned minimal
= (*alignment
)[1];
115 unsigned preferred
= alignment
->size() < 3 ? minimal
: (*alignment
)[2];
116 unsigned idx
= alignment
->size() < 4 ? size
: (*alignment
)[3];
117 return DenseIntElementsAttr::get(
118 VectorType::get({4}, IntegerType::get(context
, 32)),
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::tryToEmplaceAllocaAddrSpaceEntry(StringRef token
) {
169 StringAttr::get(context
, DLTIDialect::kDataLayoutAllocaMemorySpaceKey
);
170 if (keyEntries
.count(key
))
173 FailureOr
<unsigned> space
= tryToParseInt(token
);
177 // Only store the address space if it has a non-default value.
180 OpBuilder
builder(context
);
181 keyEntries
.try_emplace(
182 key
, DataLayoutEntryAttr::get(key
, builder
.getUI32IntegerAttr(*space
)));
187 DataLayoutImporter::tryToEmplaceStackAlignmentEntry(StringRef token
) {
189 StringAttr::get(context
, DLTIDialect::kDataLayoutStackAlignmentKey
);
190 if (keyEntries
.count(key
))
193 FailureOr
<unsigned> alignment
= tryToParseInt(token
);
194 if (failed(alignment
))
197 // Only store the stack alignment if it has a non-default value.
200 OpBuilder
builder(context
);
201 keyEntries
.try_emplace(key
, DataLayoutEntryAttr::get(
202 key
, builder
.getI32IntegerAttr(*alignment
)));
206 void DataLayoutImporter::translateDataLayout(
207 const llvm::DataLayout
&llvmDataLayout
) {
210 // Transform the data layout to its string representation and append the
211 // default data layout string specified in the language reference
212 // (https://llvm.org/docs/LangRef.html#data-layout). The translation then
213 // parses the string and ignores the default value if a specific kind occurs
214 // in both strings. Additionally, the following default values exist:
215 // - non-default address space pointer specifications default to the default
216 // address space pointer specification
217 // - the alloca address space defaults to the default address space.
218 layoutStr
= llvmDataLayout
.getStringRepresentation();
219 if (!layoutStr
.empty())
221 layoutStr
+= kDefaultDataLayout
;
222 StringRef
layout(layoutStr
);
224 // Split the data layout string into tokens separated by a dash.
225 SmallVector
<StringRef
> tokens
;
226 layout
.split(tokens
, '-');
228 for (StringRef token
: tokens
) {
230 FailureOr
<StringRef
> prefix
= tryToParseAlphaPrefix(token
);
234 // Parse the endianness.
235 if (*prefix
== "e") {
236 if (failed(tryToEmplaceEndiannessEntry(
237 DLTIDialect::kDataLayoutEndiannessLittle
, token
)))
241 if (*prefix
== "E") {
242 if (failed(tryToEmplaceEndiannessEntry(
243 DLTIDialect::kDataLayoutEndiannessBig
, token
)))
247 // Parse the alloca address space.
248 if (*prefix
== "A") {
249 if (failed(tryToEmplaceAllocaAddrSpaceEntry(token
)))
253 // Parse the stack alignment.
254 if (*prefix
== "S") {
255 if (failed(tryToEmplaceStackAlignmentEntry(token
)))
259 // Parse integer alignment specifications.
260 if (*prefix
== "i") {
261 FailureOr
<unsigned> width
= tryToParseInt(token
);
265 Type type
= IntegerType::get(context
, *width
);
266 if (failed(tryToEmplaceAlignmentEntry(type
, token
)))
270 // Parse float alignment specifications.
271 if (*prefix
== "f") {
272 FailureOr
<unsigned> width
= tryToParseInt(token
);
276 Type type
= getFloatType(context
, *width
);
277 if (failed(tryToEmplaceAlignmentEntry(type
, token
)))
281 // Parse pointer alignment specifications.
282 if (*prefix
== "p") {
283 FailureOr
<unsigned> space
=
284 token
.starts_with(":") ? 0 : tryToParseInt(token
);
288 auto type
= LLVMPointerType::get(context
, *space
);
289 if (failed(tryToEmplacePointerAlignmentEntry(type
, token
)))
294 // Store all tokens that have not been handled.
295 unhandledTokens
.push_back(lastToken
);
298 // Assemble all entries to a data layout specification.
299 SmallVector
<DataLayoutEntryInterface
> entries
;
300 entries
.reserve(typeEntries
.size() + keyEntries
.size());
301 for (const auto &it
: typeEntries
)
302 entries
.push_back(it
.second
);
303 for (const auto &it
: keyEntries
)
304 entries
.push_back(it
.second
);
305 dataLayout
= DataLayoutSpecAttr::get(context
, entries
);
308 DataLayoutSpecInterface
309 mlir::translateDataLayout(const llvm::DataLayout
&dataLayout
,
310 MLIRContext
*context
) {
311 return DataLayoutImporter(context
, dataLayout
).getDataLayout();