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 | |
19 | using namespace mlir; |
20 | using namespace mlir::LLVM; |
21 | using namespace mlir::LLVM::detail; |
22 | |
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"; |
27 | |
28 | FloatType 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 | |
46 | FailureOr<StringRef> |
47 | DataLayoutImporter::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 | |
59 | FailureOr<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 | |
66 | template <class T> |
67 | static 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 | |
80 | FailureOr<SmallVector<uint64_t>> |
81 | DataLayoutImporter::tryToParseIntList(StringRef token) const { |
82 | return tryToParseIntListImpl<uint64_t>(token); |
83 | } |
84 | |
85 | FailureOr<DenseIntElementsAttr> |
86 | DataLayoutImporter::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 | |
104 | FailureOr<DenseIntElementsAttr> |
105 | DataLayoutImporter::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 | |
127 | LogicalResult 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 | |
141 | LogicalResult |
142 | DataLayoutImporter::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 | |
156 | LogicalResult |
157 | DataLayoutImporter::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 | |
171 | LogicalResult 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 | |
186 | LogicalResult |
187 | DataLayoutImporter::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 | |
209 | LogicalResult |
210 | DataLayoutImporter::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 | |
229 | LogicalResult 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 | |
259 | LogicalResult |
260 | DataLayoutImporter::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 | |
278 | void 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 | |
416 | DataLayoutSpecInterface |
417 | mlir::translateDataLayout(const llvm::DataLayout &dataLayout, |
418 | MLIRContext *context) { |
419 | return DataLayoutImporter(context, dataLayout).getDataLayout(); |
420 | } |
421 |
Definitions
- kDefaultDataLayout
- getFloatType
- tryToParseAlphaPrefix
- tryToParseInt
- tryToParseIntListImpl
- tryToParseIntList
- tryToParseAlignment
- tryToParsePointerAlignment
- tryToEmplaceAlignmentEntry
- tryToEmplacePointerAlignmentEntry
- tryToEmplaceEndiannessEntry
- tryToEmplaceManglingModeEntry
- tryToEmplaceAddrSpaceEntry
- tryToEmplaceStackAlignmentEntry
- tryToEmplaceFunctionPointerAlignmentEntry
- tryToEmplaceLegalIntWidthsEntry
- translateDataLayout
Update your C++ knowledge – Modern C++11/14/17 Training
Find out more