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

source code of mlir/lib/Target/LLVMIR/DataLayoutImporter.cpp