MLIR  20.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 FloatType::getF16(context);
33  case 32:
34  return FloatType::getF32(context);
35  case 64:
36  return FloatType::getF64(context);
37  case 80:
38  return FloatType::getF80(context);
39  case 128:
40  return FloatType::getF128(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
167 DataLayoutImporter::tryToEmplaceAddrSpaceEntry(StringRef token,
168  llvm::StringLiteral spaceKey) {
169  auto key = StringAttr::get(context, spaceKey);
170  if (keyEntries.count(key))
171  return success();
172 
173  FailureOr<uint64_t> space = tryToParseInt(token);
174  if (failed(space))
175  return failure();
176 
177  // Only store the address space if it has a non-default value.
178  if (*space == 0)
179  return success();
180  OpBuilder builder(context);
181  keyEntries.try_emplace(
182  key,
184  key, builder.getIntegerAttr(
185  builder.getIntegerType(64, /*isSigned=*/false), *space)));
186  return success();
187 }
188 
189 LogicalResult
190 DataLayoutImporter::tryToEmplaceStackAlignmentEntry(StringRef token) {
191  auto key =
192  StringAttr::get(context, DLTIDialect::kDataLayoutStackAlignmentKey);
193  if (keyEntries.count(key))
194  return success();
195 
196  FailureOr<uint64_t> alignment = tryToParseInt(token);
197  if (failed(alignment))
198  return failure();
199 
200  // Stack alignment shouldn't be zero.
201  if (*alignment == 0)
202  return failure();
203  OpBuilder builder(context);
204  keyEntries.try_emplace(key, DataLayoutEntryAttr::get(
205  key, builder.getI64IntegerAttr(*alignment)));
206  return success();
207 }
208 
209 void DataLayoutImporter::translateDataLayout(
210  const llvm::DataLayout &llvmDataLayout) {
211  dataLayout = {};
212 
213  // Transform the data layout to its string representation and append the
214  // default data layout string specified in the language reference
215  // (https://llvm.org/docs/LangRef.html#data-layout). The translation then
216  // parses the string and ignores the default value if a specific kind occurs
217  // in both strings. Additionally, the following default values exist:
218  // - non-default address space pointer specifications default to the default
219  // address space pointer specification
220  // - the alloca address space defaults to the default address space.
221  layoutStr = llvmDataLayout.getStringRepresentation();
222  if (!layoutStr.empty())
223  layoutStr += "-";
224  layoutStr += kDefaultDataLayout;
225  StringRef layout(layoutStr);
226 
227  // Split the data layout string into tokens separated by a dash.
228  SmallVector<StringRef> tokens;
229  layout.split(tokens, '-');
230 
231  for (StringRef token : tokens) {
232  lastToken = token;
233  FailureOr<StringRef> prefix = tryToParseAlphaPrefix(token);
234  if (failed(prefix))
235  return;
236 
237  // Parse the endianness.
238  if (*prefix == "e") {
239  if (failed(tryToEmplaceEndiannessEntry(
240  DLTIDialect::kDataLayoutEndiannessLittle, token)))
241  return;
242  continue;
243  }
244  if (*prefix == "E") {
245  if (failed(tryToEmplaceEndiannessEntry(
246  DLTIDialect::kDataLayoutEndiannessBig, token)))
247  return;
248  continue;
249  }
250  // Parse the program address space.
251  if (*prefix == "P") {
252  if (failed(tryToEmplaceAddrSpaceEntry(
253  token, DLTIDialect::kDataLayoutProgramMemorySpaceKey)))
254  return;
255  continue;
256  }
257  // Parse the global address space.
258  if (*prefix == "G") {
259  if (failed(tryToEmplaceAddrSpaceEntry(
260  token, DLTIDialect::kDataLayoutGlobalMemorySpaceKey)))
261  return;
262  continue;
263  }
264  // Parse the alloca address space.
265  if (*prefix == "A") {
266  if (failed(tryToEmplaceAddrSpaceEntry(
267  token, DLTIDialect::kDataLayoutAllocaMemorySpaceKey)))
268  return;
269  continue;
270  }
271  // Parse the stack alignment.
272  if (*prefix == "S") {
273  if (failed(tryToEmplaceStackAlignmentEntry(token)))
274  return;
275  continue;
276  }
277  // Parse integer alignment specifications.
278  if (*prefix == "i") {
279  FailureOr<uint64_t> width = tryToParseInt(token);
280  if (failed(width))
281  return;
282 
283  Type type = IntegerType::get(context, *width);
284  if (failed(tryToEmplaceAlignmentEntry(type, token)))
285  return;
286  continue;
287  }
288  // Parse float alignment specifications.
289  if (*prefix == "f") {
290  FailureOr<uint64_t> width = tryToParseInt(token);
291  if (failed(width))
292  return;
293 
294  Type type = getFloatType(context, *width);
295  if (failed(tryToEmplaceAlignmentEntry(type, token)))
296  return;
297  continue;
298  }
299  // Parse pointer alignment specifications.
300  if (*prefix == "p") {
301  FailureOr<uint64_t> space =
302  token.starts_with(":") ? 0 : tryToParseInt(token);
303  if (failed(space))
304  return;
305 
306  auto type = LLVMPointerType::get(context, *space);
307  if (failed(tryToEmplacePointerAlignmentEntry(type, token)))
308  return;
309  continue;
310  }
311 
312  // Store all tokens that have not been handled.
313  unhandledTokens.push_back(lastToken);
314  }
315 
316  // Assemble all entries to a data layout specification.
318  entries.reserve(typeEntries.size() + keyEntries.size());
319  for (const auto &it : typeEntries)
320  entries.push_back(it.second);
321  for (const auto &it : keyEntries)
322  entries.push_back(it.second);
323  dataLayout = DataLayoutSpecAttr::get(context, entries);
324 }
325 
326 DataLayoutSpecInterface
327 mlir::translateDataLayout(const llvm::DataLayout &dataLayout,
328  MLIRContext *context) {
329  return DataLayoutImporter(context, dataLayout).getDataLayout();
330 }
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.
static FloatType getF64(MLIRContext *ctx)
Definition: BuiltinTypes.h:488
static FloatType getF80(MLIRContext *ctx)
Definition: BuiltinTypes.h:492
static FloatType getF16(MLIRContext *ctx)
Definition: BuiltinTypes.h:476
static FloatType getF128(MLIRContext *ctx)
Definition: BuiltinTypes.h:496
static FloatType getF32(MLIRContext *ctx)
Definition: BuiltinTypes.h:484
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:215
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...