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/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"
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
28FloatType mlir::LLVM::detail::getFloatType(MLIRContext *context,
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(F: isalpha);
52 if (prefix.empty())
53 return failure();
54
55 token.consume_front(Prefix: prefix);
56 return prefix;
57}
58
59FailureOr<uint64_t> DataLayoutImporter::tryToParseInt(StringRef &token) const {
60 uint64_t parameter;
61 if (token.consumeInteger(/*Radix=*/10, Result&: parameter))
62 return failure();
63 return parameter;
64}
65
66template <class T>
67static FailureOr<SmallVector<T>> tryToParseIntListImpl(StringRef token) {
68 SmallVector<StringRef> tokens;
69 token.consume_front(Prefix: ":");
70 token.split(A&: tokens, Separator: ':');
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 {
82 return tryToParseIntListImpl<uint64_t>(token);
83}
84
85FailureOr<DenseIntElementsAttr>
86DataLayoutImporter::tryToParseAlignment(StringRef token) const {
87 FailureOr<SmallVector<uint64_t>> alignment = tryToParseIntList(token);
88 if (failed(Result: 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];
99 return DenseIntElementsAttr::get(
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(Result: 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];
122 return DenseIntElementsAttr::get<uint64_t>(
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: key))
131 return success();
132
133 FailureOr<DenseIntElementsAttr> params = tryToParseAlignment(token);
134 if (failed(Result: 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: key))
146 return success();
147
148 FailureOr<DenseIntElementsAttr> params = tryToParsePointerAlignment(token);
149 if (failed(Result: 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: 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: key))
175 return success();
176
177 token.consume_front(Prefix: ":");
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: key))
191 return success();
192
193 FailureOr<uint64_t> space = tryToParseInt(token);
194 if (failed(Result: 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: key))
214 return success();
215
216 FailureOr<uint64_t> alignment = tryToParseInt(token);
217 if (failed(Result: 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: 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(Result: 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: key))
264 return success();
265
266 FailureOr<SmallVector<int32_t>> intWidths =
267 tryToParseIntListImpl<int32_t>(token);
268 if (failed(Result: 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
278void DataLayoutImporter::translateDataLayout(
279 const llvm::DataLayout &llvmDataLayout) {
280 dataLayout = {};
281
282 // Transform the data layout to its string representation and append the
283 // default data layout string specified in the language reference
284 // (https://llvm.org/docs/LangRef.html#data-layout). The translation then
285 // parses the string and ignores the default value if a specific kind occurs
286 // in both strings. Additionally, the following default values exist:
287 // - non-default address space pointer specifications default to the default
288 // address space pointer specification
289 // - the alloca address space defaults to the default address space.
290 layoutStr = llvmDataLayout.getStringRepresentation();
291 if (!layoutStr.empty())
292 layoutStr += "-";
293 layoutStr += kDefaultDataLayout;
294 StringRef layout(layoutStr);
295
296 // Split the data layout string into tokens separated by a dash.
297 SmallVector<StringRef> tokens;
298 layout.split(A&: tokens, Separator: '-');
299
300 for (StringRef token : tokens) {
301 lastToken = token;
302 FailureOr<StringRef> prefix = tryToParseAlphaPrefix(token);
303 if (failed(Result: prefix))
304 return;
305
306 // Parse the endianness.
307 if (*prefix == "e") {
308 if (failed(tryToEmplaceEndiannessEntry(
309 DLTIDialect::kDataLayoutEndiannessLittle, token)))
310 return;
311 continue;
312 }
313 if (*prefix == "E") {
314 if (failed(tryToEmplaceEndiannessEntry(
315 DLTIDialect::kDataLayoutEndiannessBig, token)))
316 return;
317 continue;
318 }
319 // Parse the program address space.
320 if (*prefix == "P") {
321 if (failed(tryToEmplaceAddrSpaceEntry(
322 token, DLTIDialect::kDataLayoutProgramMemorySpaceKey)))
323 return;
324 continue;
325 }
326 // Parse the mangling mode.
327 if (*prefix == "m") {
328 if (failed(tryToEmplaceManglingModeEntry(
329 token, DLTIDialect::kDataLayoutManglingModeKey)))
330 return;
331 continue;
332 }
333 // Parse the global address space.
334 if (*prefix == "G") {
335 if (failed(tryToEmplaceAddrSpaceEntry(
336 token, DLTIDialect::kDataLayoutGlobalMemorySpaceKey)))
337 return;
338 continue;
339 }
340 // Parse the alloca address space.
341 if (*prefix == "A") {
342 if (failed(tryToEmplaceAddrSpaceEntry(
343 token, DLTIDialect::kDataLayoutAllocaMemorySpaceKey)))
344 return;
345 continue;
346 }
347 // Parse the stack alignment.
348 if (*prefix == "S") {
349 if (failed(Result: tryToEmplaceStackAlignmentEntry(token)))
350 return;
351 continue;
352 }
353 // Parse integer alignment specifications.
354 if (*prefix == "i") {
355 FailureOr<uint64_t> width = tryToParseInt(token);
356 if (failed(Result: width))
357 return;
358
359 Type type = IntegerType::get(context, *width);
360 if (failed(Result: tryToEmplaceAlignmentEntry(type, token)))
361 return;
362 continue;
363 }
364 // Parse float alignment specifications.
365 if (*prefix == "f") {
366 FailureOr<uint64_t> width = tryToParseInt(token);
367 if (failed(Result: width))
368 return;
369
370 Type type = getFloatType(context, *width);
371 if (failed(Result: tryToEmplaceAlignmentEntry(type, token)))
372 return;
373 continue;
374 }
375 // Parse pointer alignment specifications.
376 if (*prefix == "p") {
377 FailureOr<uint64_t> space =
378 token.starts_with(Prefix: ":") ? 0 : tryToParseInt(token);
379 if (failed(Result: space))
380 return;
381
382 auto type = LLVMPointerType::get(context, *space);
383 if (failed(tryToEmplacePointerAlignmentEntry(type, token)))
384 return;
385 continue;
386 }
387 // Parse native integer widths specifications.
388 if (*prefix == "n") {
389 if (failed(Result: tryToEmplaceLegalIntWidthsEntry(token)))
390 return;
391 continue;
392 }
393 // Parse function pointer alignment specifications.
394 // Note that prefix here is "Fn" or "Fi", not a single character.
395 if (prefix->starts_with(Prefix: "F")) {
396 StringRef nextPrefix = prefix->drop_front(N: 1);
397 if (failed(Result: tryToEmplaceFunctionPointerAlignmentEntry(fnPtrString: nextPrefix, token)))
398 return;
399 continue;
400 }
401
402 // Store all tokens that have not been handled.
403 unhandledTokens.push_back(Elt: lastToken);
404 }
405
406 // Assemble all entries to a data layout specification.
407 SmallVector<DataLayoutEntryInterface> entries;
408 entries.reserve(typeEntries.size() + keyEntries.size());
409 for (const auto &it : typeEntries)
410 entries.push_back(it.second);
411 for (const auto &it : keyEntries)
412 entries.push_back(it.second);
413 dataLayout = DataLayoutSpecAttr::get(context, entries);
414}
415
416DataLayoutSpecInterface
417mlir::translateDataLayout(const llvm::DataLayout &dataLayout,
418 MLIRContext *context) {
419 return DataLayoutImporter(context, dataLayout).getDataLayout();
420}
421

Provided by KDAB

Privacy Policy
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more

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