MLIR  21.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 
9 #include "DataLayoutImporter.h"
10 #include "mlir/Dialect/DLTI/DLTI.h"
12 #include "mlir/IR/Builders.h"
14 #include "mlir/IR/BuiltinTypes.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 
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(isalpha);
52  if (prefix.empty())
53  return failure();
54 
55  token.consume_front(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, parameter))
62  return failure();
63  return parameter;
64 }
65 
66 template <class T>
67 static 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 
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(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 
104 FailureOr<DenseIntElementsAttr>
105 DataLayoutImporter::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];
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))
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 
141 LogicalResult
142 DataLayoutImporter::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 
156 LogicalResult
157 DataLayoutImporter::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 
171 LogicalResult 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 
186 LogicalResult
187 DataLayoutImporter::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,
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))
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 
229 LogicalResult 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(
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))
264  return success();
265 
266  FailureOr<SmallVector<int32_t>> intWidths =
267  tryToParseIntListImpl<int32_t>(token);
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 
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(tokens, '-');
299 
300  for (StringRef token : tokens) {
301  lastToken = token;
302  FailureOr<StringRef> prefix = tryToParseAlphaPrefix(token);
303  if (failed(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(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(width))
357  return;
358 
359  Type type = IntegerType::get(context, *width);
360  if (failed(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(width))
368  return;
369 
370  Type type = getFloatType(context, *width);
371  if (failed(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(":") ? 0 : tryToParseInt(token);
379  if (failed(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(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("F")) {
396  StringRef nextPrefix = prefix->drop_front(1);
397  if (failed(tryToEmplaceFunctionPointerAlignmentEntry(nextPrefix, token)))
398  return;
399  continue;
400  }
401 
402  // Store all tokens that have not been handled.
403  unhandledTokens.push_back(lastToken);
404  }
405 
406  // Assemble all entries to a data layout specification.
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 }
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 to an MLIR data layout specification.
DataLayoutSpecInterface getDataLayout() 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:60
This class helps build Operations.
Definition: Builders.h:204
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition: Types.h:74
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...
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.
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...