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 FailureOr<SmallVector<uint64_t>>
67 DataLayoutImporter::tryToParseIntList(StringRef token) const {
69  token.consume_front(":");
70  token.split(tokens, ':');
71 
72  // Parse an integer list.
73  SmallVector<uint64_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<DenseIntElementsAttr>
81 DataLayoutImporter::tryToParseAlignment(StringRef token) const {
82  FailureOr<SmallVector<uint64_t>> alignment = tryToParseIntList(token);
83  if (failed(alignment))
84  return failure();
85  if (alignment->empty() || alignment->size() > 2)
86  return failure();
87 
88  // Alignment specifications (such as 32 or 32:64) are of the
89  // form <abi>[:<pref>], where abi specifies the minimal alignment and pref the
90  // optional preferred alignment. The preferred alignment is set to the minimal
91  // alignment if not available.
92  uint64_t minimal = (*alignment)[0];
93  uint64_t preferred = alignment->size() == 1 ? minimal : (*alignment)[1];
95  VectorType::get({2}, IntegerType::get(context, 64)),
96  {minimal, preferred});
97 }
98 
99 FailureOr<DenseIntElementsAttr>
100 DataLayoutImporter::tryToParsePointerAlignment(StringRef token) const {
101  FailureOr<SmallVector<uint64_t>> alignment = tryToParseIntList(token);
102  if (failed(alignment))
103  return failure();
104  if (alignment->size() < 2 || alignment->size() > 4)
105  return failure();
106 
107  // Pointer alignment specifications (such as 64:32:64:32 or 32:32) are of
108  // the form <size>:<abi>[:<pref>][:<idx>], where size is the pointer size, abi
109  // specifies the minimal alignment, pref the optional preferred alignment, and
110  // idx the optional index computation bit width. The preferred alignment is
111  // set to the minimal alignment if not available and the index computation
112  // width is set to the pointer size if not available.
113  uint64_t size = (*alignment)[0];
114  uint64_t minimal = (*alignment)[1];
115  uint64_t preferred = alignment->size() < 3 ? minimal : (*alignment)[2];
116  uint64_t idx = alignment->size() < 4 ? size : (*alignment)[3];
117  return DenseIntElementsAttr::get<uint64_t>(
118  VectorType::get({4}, IntegerType::get(context, 64)),
119  {size, minimal, preferred, idx});
120 }
121 
122 LogicalResult DataLayoutImporter::tryToEmplaceAlignmentEntry(Type type,
123  StringRef token) {
124  auto key = TypeAttr::get(type);
125  if (typeEntries.count(key))
126  return success();
127 
128  FailureOr<DenseIntElementsAttr> params = tryToParseAlignment(token);
129  if (failed(params))
130  return failure();
131 
132  typeEntries.try_emplace(key, DataLayoutEntryAttr::get(type, *params));
133  return success();
134 }
135 
136 LogicalResult
137 DataLayoutImporter::tryToEmplacePointerAlignmentEntry(LLVMPointerType type,
138  StringRef token) {
139  auto key = TypeAttr::get(type);
140  if (typeEntries.count(key))
141  return success();
142 
143  FailureOr<DenseIntElementsAttr> params = tryToParsePointerAlignment(token);
144  if (failed(params))
145  return failure();
146 
147  typeEntries.try_emplace(key, DataLayoutEntryAttr::get(type, *params));
148  return success();
149 }
150 
151 LogicalResult
152 DataLayoutImporter::tryToEmplaceEndiannessEntry(StringRef endianness,
153  StringRef token) {
154  auto key = StringAttr::get(context, DLTIDialect::kDataLayoutEndiannessKey);
155  if (keyEntries.count(key))
156  return success();
157 
158  if (!token.empty())
159  return failure();
160 
161  keyEntries.try_emplace(
162  key, DataLayoutEntryAttr::get(key, StringAttr::get(context, endianness)));
163  return success();
164 }
165 
166 LogicalResult DataLayoutImporter::tryToEmplaceManglingModeEntry(
167  StringRef token, llvm::StringLiteral manglingKey) {
168  auto key = StringAttr::get(context, manglingKey);
169  if (keyEntries.count(key))
170  return success();
171 
172  token.consume_front(":");
173  if (token.empty())
174  return failure();
175 
176  keyEntries.try_emplace(
177  key, DataLayoutEntryAttr::get(key, StringAttr::get(context, token)));
178  return success();
179 }
180 
181 LogicalResult
182 DataLayoutImporter::tryToEmplaceAddrSpaceEntry(StringRef token,
183  llvm::StringLiteral spaceKey) {
184  auto key = StringAttr::get(context, spaceKey);
185  if (keyEntries.count(key))
186  return success();
187 
188  FailureOr<uint64_t> space = tryToParseInt(token);
189  if (failed(space))
190  return failure();
191 
192  // Only store the address space if it has a non-default value.
193  if (*space == 0)
194  return success();
195  OpBuilder builder(context);
196  keyEntries.try_emplace(
197  key,
199  key, builder.getIntegerAttr(
200  builder.getIntegerType(64, /*isSigned=*/false), *space)));
201  return success();
202 }
203 
204 LogicalResult
205 DataLayoutImporter::tryToEmplaceStackAlignmentEntry(StringRef token) {
206  auto key =
207  StringAttr::get(context, DLTIDialect::kDataLayoutStackAlignmentKey);
208  if (keyEntries.count(key))
209  return success();
210 
211  FailureOr<uint64_t> alignment = tryToParseInt(token);
212  if (failed(alignment))
213  return failure();
214 
215  // Stack alignment shouldn't be zero.
216  if (*alignment == 0)
217  return failure();
218  OpBuilder builder(context);
219  keyEntries.try_emplace(key, DataLayoutEntryAttr::get(
220  key, builder.getI64IntegerAttr(*alignment)));
221  return success();
222 }
223 
224 LogicalResult DataLayoutImporter::tryToEmplaceFunctionPointerAlignmentEntry(
225  StringRef fnPtrString, StringRef token) {
226  auto key = StringAttr::get(
227  context, DLTIDialect::kDataLayoutFunctionPointerAlignmentKey);
228  if (keyEntries.count(key))
229  return success();
230 
231  // The data layout entry for "F<type><abi>". <abi> is the aligment value,
232  // preceded by one of the two possible <types>:
233  // "i": The alignment of function pointers is independent of the alignment of
234  // functions, and is a multiple of <abi>.
235  // "n": The alignment of function pointers is a multiple of the explicit
236  // alignment specified on the function, and is a multiple of <abi>.
237  bool functionDependent = false;
238  if (fnPtrString == "n")
239  functionDependent = true;
240  else if (fnPtrString != "i")
241  return failure();
242 
243  FailureOr<uint64_t> alignment = tryToParseInt(token);
244  if (failed(alignment))
245  return failure();
246 
247  keyEntries.try_emplace(
250  key.getContext(), *alignment, functionDependent)));
251  return success();
252 }
253 
254 void DataLayoutImporter::translateDataLayout(
255  const llvm::DataLayout &llvmDataLayout) {
256  dataLayout = {};
257 
258  // Transform the data layout to its string representation and append the
259  // default data layout string specified in the language reference
260  // (https://llvm.org/docs/LangRef.html#data-layout). The translation then
261  // parses the string and ignores the default value if a specific kind occurs
262  // in both strings. Additionally, the following default values exist:
263  // - non-default address space pointer specifications default to the default
264  // address space pointer specification
265  // - the alloca address space defaults to the default address space.
266  layoutStr = llvmDataLayout.getStringRepresentation();
267  if (!layoutStr.empty())
268  layoutStr += "-";
269  layoutStr += kDefaultDataLayout;
270  StringRef layout(layoutStr);
271 
272  // Split the data layout string into tokens separated by a dash.
273  SmallVector<StringRef> tokens;
274  layout.split(tokens, '-');
275 
276  for (StringRef token : tokens) {
277  lastToken = token;
278  FailureOr<StringRef> prefix = tryToParseAlphaPrefix(token);
279  if (failed(prefix))
280  return;
281 
282  // Parse the endianness.
283  if (*prefix == "e") {
284  if (failed(tryToEmplaceEndiannessEntry(
285  DLTIDialect::kDataLayoutEndiannessLittle, token)))
286  return;
287  continue;
288  }
289  if (*prefix == "E") {
290  if (failed(tryToEmplaceEndiannessEntry(
291  DLTIDialect::kDataLayoutEndiannessBig, token)))
292  return;
293  continue;
294  }
295  // Parse the program address space.
296  if (*prefix == "P") {
297  if (failed(tryToEmplaceAddrSpaceEntry(
298  token, DLTIDialect::kDataLayoutProgramMemorySpaceKey)))
299  return;
300  continue;
301  }
302  // Parse the mangling mode.
303  if (*prefix == "m") {
304  if (failed(tryToEmplaceManglingModeEntry(
305  token, DLTIDialect::kDataLayoutManglingModeKey)))
306  return;
307  continue;
308  }
309  // Parse the global address space.
310  if (*prefix == "G") {
311  if (failed(tryToEmplaceAddrSpaceEntry(
312  token, DLTIDialect::kDataLayoutGlobalMemorySpaceKey)))
313  return;
314  continue;
315  }
316  // Parse the alloca address space.
317  if (*prefix == "A") {
318  if (failed(tryToEmplaceAddrSpaceEntry(
319  token, DLTIDialect::kDataLayoutAllocaMemorySpaceKey)))
320  return;
321  continue;
322  }
323  // Parse the stack alignment.
324  if (*prefix == "S") {
325  if (failed(tryToEmplaceStackAlignmentEntry(token)))
326  return;
327  continue;
328  }
329  // Parse integer alignment specifications.
330  if (*prefix == "i") {
331  FailureOr<uint64_t> width = tryToParseInt(token);
332  if (failed(width))
333  return;
334 
335  Type type = IntegerType::get(context, *width);
336  if (failed(tryToEmplaceAlignmentEntry(type, token)))
337  return;
338  continue;
339  }
340  // Parse float alignment specifications.
341  if (*prefix == "f") {
342  FailureOr<uint64_t> width = tryToParseInt(token);
343  if (failed(width))
344  return;
345 
346  Type type = getFloatType(context, *width);
347  if (failed(tryToEmplaceAlignmentEntry(type, token)))
348  return;
349  continue;
350  }
351  // Parse pointer alignment specifications.
352  if (*prefix == "p") {
353  FailureOr<uint64_t> space =
354  token.starts_with(":") ? 0 : tryToParseInt(token);
355  if (failed(space))
356  return;
357 
358  auto type = LLVMPointerType::get(context, *space);
359  if (failed(tryToEmplacePointerAlignmentEntry(type, token)))
360  return;
361  continue;
362  }
363  // Parse function pointer alignment specifications.
364  // Note that prefix here is "Fn" or "Fi", not a single character.
365  if (prefix->starts_with("F")) {
366  StringRef nextPrefix = prefix->drop_front(1);
367  if (failed(tryToEmplaceFunctionPointerAlignmentEntry(nextPrefix, token)))
368  return;
369  continue;
370  }
371 
372  // Store all tokens that have not been handled.
373  unhandledTokens.push_back(lastToken);
374  }
375 
376  // Assemble all entries to a data layout specification.
378  entries.reserve(typeEntries.size() + keyEntries.size());
379  for (const auto &it : typeEntries)
380  entries.push_back(it.second);
381  for (const auto &it : keyEntries)
382  entries.push_back(it.second);
383  dataLayout = DataLayoutSpecAttr::get(context, entries);
384 }
385 
386 DataLayoutSpecInterface
387 mlir::translateDataLayout(const llvm::DataLayout &dataLayout,
388  MLIRContext *context) {
389  return DataLayoutImporter(context, dataLayout).getDataLayout();
390 }
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...