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 
10 #include "mlir/Dialect/DLTI/DLTI.h"
11 #include "mlir/IR/Builders.h"
13 #include "mlir/IR/BuiltinTypes.h"
16 
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 DataLayoutSpecInterface 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.
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 
403 DataLayoutSpecInterface
404 mlir::translateDataLayout(const llvm::DataLayout &dataLayout,
405  MLIRContext *context) {
406  return DataLayoutImporter(context, dataLayout.getStringRepresentation())
408 }
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
This class helps build Operations.
Definition: Builders.h:205
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...
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition: Remarks.h:491
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...