MLIR 22.0.0git
DataLayoutImporter.cpp
Go to the documentation of this file.
1//===- DataLayoutImporter.cpp - LLVM to MLIR data layout conversion -------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8
11#include "mlir/IR/Builders.h"
16
17#include "llvm/IR/DataLayout.h"
18
19using namespace mlir;
20using namespace mlir::LLVM;
21using namespace mlir::LLVM::detail;
22
23/// The default data layout used during the translation.
24static 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";
27
29 unsigned width) {
30 switch (width) {
31 case 16:
32 return Float16Type::get(context);
33 case 32:
34 return Float32Type::get(context);
35 case 64:
36 return Float64Type::get(context);
37 case 80:
38 return Float80Type::get(context);
39 case 128:
40 return Float128Type::get(context);
41 default:
42 return {};
43 }
44}
45
46FailureOr<StringRef>
47DataLayoutImporter::tryToParseAlphaPrefix(StringRef &token) const {
48 if (token.empty())
49 return failure();
50
51 StringRef prefix = token.take_while(isalpha);
52 if (prefix.empty())
53 return failure();
54
55 token.consume_front(prefix);
56 return prefix;
57}
58
59FailureOr<uint64_t> DataLayoutImporter::tryToParseInt(StringRef &token) const {
60 uint64_t parameter;
61 if (token.consumeInteger(/*Radix=*/10, parameter))
62 return failure();
63 return parameter;
64}
65
66template <class T>
67static FailureOr<SmallVector<T>> tryToParseIntListImpl(StringRef token) {
69 token.consume_front(":");
70 token.split(tokens, ':');
71
72 // Parse an integer list.
73 SmallVector<T> results(tokens.size());
74 for (auto [result, token] : llvm::zip(results, tokens))
75 if (token.getAsInteger(/*Radix=*/10, result))
76 return failure();
77 return results;
78}
79
80FailureOr<SmallVector<uint64_t>>
81DataLayoutImporter::tryToParseIntList(StringRef token) const {
83}
84
85FailureOr<DenseIntElementsAttr>
86DataLayoutImporter::tryToParseAlignment(StringRef token) const {
87 FailureOr<SmallVector<uint64_t>> alignment = tryToParseIntList(token);
88 if (failed(alignment))
89 return failure();
90 if (alignment->empty() || alignment->size() > 2)
91 return failure();
92
93 // Alignment specifications (such as 32 or 32:64) are of the
94 // form <abi>[:<pref>], where abi specifies the minimal alignment and pref the
95 // optional preferred alignment. The preferred alignment is set to the minimal
96 // alignment if not available.
97 uint64_t minimal = (*alignment)[0];
98 uint64_t preferred = alignment->size() == 1 ? minimal : (*alignment)[1];
100 VectorType::get({2}, IntegerType::get(context, 64)),
101 {minimal, preferred});
102}
103
104FailureOr<DenseIntElementsAttr>
105DataLayoutImporter::tryToParsePointerAlignment(StringRef token) const {
106 FailureOr<SmallVector<uint64_t>> alignment = tryToParseIntList(token);
107 if (failed(alignment))
108 return failure();
109 if (alignment->size() < 2 || alignment->size() > 4)
110 return failure();
111
112 // Pointer alignment specifications (such as 64:32:64:32 or 32:32) are of
113 // the form <size>:<abi>[:<pref>][:<idx>], where size is the pointer size, abi
114 // specifies the minimal alignment, pref the optional preferred alignment, and
115 // idx the optional index computation bit width. The preferred alignment is
116 // set to the minimal alignment if not available and the index computation
117 // width is set to the pointer size if not available.
118 uint64_t size = (*alignment)[0];
119 uint64_t minimal = (*alignment)[1];
120 uint64_t preferred = alignment->size() < 3 ? minimal : (*alignment)[2];
121 uint64_t idx = alignment->size() < 4 ? size : (*alignment)[3];
123 VectorType::get({4}, IntegerType::get(context, 64)),
124 {size, minimal, preferred, idx});
125}
126
127LogicalResult DataLayoutImporter::tryToEmplaceAlignmentEntry(Type type,
128 StringRef token) {
129 auto key = TypeAttr::get(type);
130 if (typeEntries.count(key))
131 return success();
132
133 FailureOr<DenseIntElementsAttr> params = tryToParseAlignment(token);
134 if (failed(params))
135 return failure();
136
137 typeEntries.try_emplace(key, DataLayoutEntryAttr::get(type, *params));
138 return success();
139}
140
141LogicalResult
142DataLayoutImporter::tryToEmplacePointerAlignmentEntry(LLVMPointerType type,
143 StringRef token) {
144 auto key = TypeAttr::get(type);
145 if (typeEntries.count(key))
146 return success();
147
148 FailureOr<DenseIntElementsAttr> params = tryToParsePointerAlignment(token);
149 if (failed(params))
150 return failure();
151
152 typeEntries.try_emplace(key, DataLayoutEntryAttr::get(type, *params));
153 return success();
154}
155
156LogicalResult
157DataLayoutImporter::tryToEmplaceEndiannessEntry(StringRef endianness,
158 StringRef token) {
159 auto key = StringAttr::get(context, DLTIDialect::kDataLayoutEndiannessKey);
160 if (keyEntries.count(key))
161 return success();
162
163 if (!token.empty())
164 return failure();
165
166 keyEntries.try_emplace(
167 key, DataLayoutEntryAttr::get(key, StringAttr::get(context, endianness)));
168 return success();
169}
170
171LogicalResult DataLayoutImporter::tryToEmplaceManglingModeEntry(
172 StringRef token, llvm::StringLiteral manglingKey) {
173 auto key = StringAttr::get(context, manglingKey);
174 if (keyEntries.count(key))
175 return success();
176
177 token.consume_front(":");
178 if (token.empty())
179 return failure();
180
181 keyEntries.try_emplace(
182 key, DataLayoutEntryAttr::get(key, StringAttr::get(context, token)));
183 return success();
184}
185
186LogicalResult
187DataLayoutImporter::tryToEmplaceAddrSpaceEntry(StringRef token,
188 llvm::StringLiteral spaceKey) {
189 auto key = StringAttr::get(context, spaceKey);
190 if (keyEntries.count(key))
191 return success();
192
193 FailureOr<uint64_t> space = tryToParseInt(token);
194 if (failed(space))
195 return failure();
196
197 // Only store the address space if it has a non-default value.
198 if (*space == 0)
199 return success();
200 OpBuilder builder(context);
201 keyEntries.try_emplace(
202 key,
203 DataLayoutEntryAttr::get(
204 key, builder.getIntegerAttr(
205 builder.getIntegerType(64, /*isSigned=*/false), *space)));
206 return success();
207}
208
209LogicalResult
210DataLayoutImporter::tryToEmplaceStackAlignmentEntry(StringRef token) {
211 auto key =
212 StringAttr::get(context, DLTIDialect::kDataLayoutStackAlignmentKey);
213 if (keyEntries.count(key))
214 return success();
215
216 FailureOr<uint64_t> alignment = tryToParseInt(token);
217 if (failed(alignment))
218 return failure();
219
220 // Stack alignment shouldn't be zero.
221 if (*alignment == 0)
222 return failure();
223 OpBuilder builder(context);
224 keyEntries.try_emplace(key, DataLayoutEntryAttr::get(
225 key, builder.getI64IntegerAttr(*alignment)));
226 return success();
227}
228
229LogicalResult DataLayoutImporter::tryToEmplaceFunctionPointerAlignmentEntry(
230 StringRef fnPtrString, StringRef token) {
231 auto key = StringAttr::get(
232 context, DLTIDialect::kDataLayoutFunctionPointerAlignmentKey);
233 if (keyEntries.count(key))
234 return success();
235
236 // The data layout entry for "F<type><abi>". <abi> is the aligment value,
237 // preceded by one of the two possible <types>:
238 // "i": The alignment of function pointers is independent of the alignment of
239 // functions, and is a multiple of <abi>.
240 // "n": The alignment of function pointers is a multiple of the explicit
241 // alignment specified on the function, and is a multiple of <abi>.
242 bool functionDependent = false;
243 if (fnPtrString == "n")
244 functionDependent = true;
245 else if (fnPtrString != "i")
246 return failure();
247
248 FailureOr<uint64_t> alignment = tryToParseInt(token);
249 if (failed(alignment))
250 return failure();
251
252 keyEntries.try_emplace(
253 key, DataLayoutEntryAttr::get(
254 key, FunctionPointerAlignmentAttr::get(
255 key.getContext(), *alignment, functionDependent)));
256 return success();
257}
258
259LogicalResult
260DataLayoutImporter::tryToEmplaceLegalIntWidthsEntry(StringRef token) {
261 auto key =
262 StringAttr::get(context, DLTIDialect::kDataLayoutLegalIntWidthsKey);
263 if (keyEntries.count(key))
264 return success();
265
266 FailureOr<SmallVector<int32_t>> intWidths =
268 if (failed(intWidths) || intWidths->empty())
269 return failure();
270
271 OpBuilder builder(context);
272 keyEntries.try_emplace(
273 key,
274 DataLayoutEntryAttr::get(key, builder.getDenseI32ArrayAttr(*intWidths)));
275 return success();
276}
277
278DataLayoutSpecInterface DataLayoutImporter::dataLayoutSpecFromDataLayoutStr() {
279 if (!dataLayoutStr.empty())
280 dataLayoutStr += "-";
281 dataLayoutStr += kDefaultDataLayout;
282
283 // Split the data layout string into tokens separated by a dash.
284 SmallVector<StringRef> tokens;
285 StringRef(dataLayoutStr).split(tokens, '-');
286
287 for (StringRef token : tokens) {
288 lastToken = token;
289 FailureOr<StringRef> prefix = tryToParseAlphaPrefix(token);
290 if (failed(prefix))
291 return {};
292
293 // Parse the endianness.
294 if (*prefix == "e") {
295 if (failed(tryToEmplaceEndiannessEntry(
296 DLTIDialect::kDataLayoutEndiannessLittle, token)))
297 return {};
298 continue;
299 }
300 if (*prefix == "E") {
301 if (failed(tryToEmplaceEndiannessEntry(
302 DLTIDialect::kDataLayoutEndiannessBig, token)))
303 return {};
304 continue;
305 }
306 // Parse the program address space.
307 if (*prefix == "P") {
308 if (failed(tryToEmplaceAddrSpaceEntry(
309 token, DLTIDialect::kDataLayoutProgramMemorySpaceKey)))
310 return {};
311 continue;
312 }
313 // Parse the mangling mode.
314 if (*prefix == "m") {
315 if (failed(tryToEmplaceManglingModeEntry(
316 token, DLTIDialect::kDataLayoutManglingModeKey)))
317 return {};
318 continue;
319 }
320 // Parse the global address space.
321 if (*prefix == "G") {
322 if (failed(tryToEmplaceAddrSpaceEntry(
323 token, DLTIDialect::kDataLayoutGlobalMemorySpaceKey)))
324 return {};
325 continue;
326 }
327 // Parse the alloca address space.
328 if (*prefix == "A") {
329 if (failed(tryToEmplaceAddrSpaceEntry(
330 token, DLTIDialect::kDataLayoutAllocaMemorySpaceKey)))
331 return {};
332 continue;
333 }
334 // Parse the stack alignment.
335 if (*prefix == "S") {
336 if (failed(tryToEmplaceStackAlignmentEntry(token)))
337 return {};
338 continue;
339 }
340 // Parse integer alignment specifications.
341 if (*prefix == "i") {
342 FailureOr<uint64_t> width = tryToParseInt(token);
343 if (failed(width))
344 return {};
345
346 Type type = IntegerType::get(context, *width);
347 if (failed(tryToEmplaceAlignmentEntry(type, token)))
348 return {};
349 continue;
350 }
351 // Parse float alignment specifications.
352 if (*prefix == "f") {
353 FailureOr<uint64_t> width = tryToParseInt(token);
354 if (failed(width))
355 return {};
356
357 Type type = getFloatType(context, *width);
358 if (failed(tryToEmplaceAlignmentEntry(type, token)))
359 return {};
360 continue;
361 }
362 // Parse pointer alignment specifications.
363 if (*prefix == "p") {
364 FailureOr<uint64_t> space =
365 token.starts_with(":") ? 0 : tryToParseInt(token);
366 if (failed(space))
367 return {};
368
369 auto type = LLVMPointerType::get(context, *space);
370 if (failed(tryToEmplacePointerAlignmentEntry(type, token)))
371 return {};
372 continue;
373 }
374 // Parse native integer widths specifications.
375 if (*prefix == "n") {
376 if (failed(tryToEmplaceLegalIntWidthsEntry(token)))
377 return {};
378 continue;
379 }
380 // Parse function pointer alignment specifications.
381 // Note that prefix here is "Fn" or "Fi", not a single character.
382 if (prefix->starts_with("F")) {
383 StringRef nextPrefix = prefix->drop_front(1);
384 if (failed(tryToEmplaceFunctionPointerAlignmentEntry(nextPrefix, token)))
385 return {};
386 continue;
387 }
388
389 // Store all tokens that have not been handled.
390 unhandledTokens.push_back(lastToken);
391 }
392
393 // Assemble all entries to a data layout specification.
394 SmallVector<DataLayoutEntryInterface> entries;
395 entries.reserve(typeEntries.size() + keyEntries.size());
396 for (const auto &it : typeEntries)
397 entries.push_back(it.second);
398 for (const auto &it : keyEntries)
399 entries.push_back(it.second);
400 return DataLayoutSpecAttr::get(context, entries);
401}
402
403DataLayoutSpecInterface
404mlir::translateDataLayout(const llvm::DataLayout &dataLayout,
405 MLIRContext *context) {
406 return DataLayoutImporter(context, dataLayout.getStringRepresentation())
408}
return success()
static FailureOr< SmallVector< T > > tryToParseIntListImpl(StringRef token)
static constexpr StringRef kDefaultDataLayout
The default data layout used during the translation.
static DenseIntElementsAttr get(const ShapedType &type, Arg &&arg)
Get an instance of a DenseIntElementsAttr with the given arguments.
Helper class that translates an LLVM data layout string to an MLIR data layout specification.
DataLayoutSpecInterface getDataLayoutSpec() const
Returns the MLIR data layout specification translated from the LLVM data layout.
MLIRContext is the top-level object for a collection of MLIR operations.
Definition MLIRContext.h:63
FloatType getFloatType(MLIRContext *context, unsigned width)
Returns a supported MLIR floating point type of the given bit width or null if the bit width is not s...
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition Remarks.h:561
Include the generated interface declarations.
DataLayoutSpecInterface translateDataLayout(const llvm::DataLayout &dataLayout, MLIRContext *context)
Translate the given LLVM data layout into an MLIR equivalent using the DLTI dialect.