MLIR  21.0.0git
DataLayoutInterfaces.cpp
Go to the documentation of this file.
1 //===- DataLayoutInterfaces.cpp - Data Layout Interface Implementation ----===//
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/IR/BuiltinDialect.h"
11 #include "mlir/IR/BuiltinOps.h"
12 #include "mlir/IR/BuiltinTypes.h"
13 #include "mlir/IR/Operation.h"
14 
15 #include "llvm/ADT/TypeSwitch.h"
16 #include "llvm/Support/MathExtras.h"
17 
18 using namespace mlir;
19 
20 //===----------------------------------------------------------------------===//
21 // Default implementations
22 //===----------------------------------------------------------------------===//
23 
24 /// Reports that the given type is missing the data layout information and
25 /// exits.
26 [[noreturn]] static void reportMissingDataLayout(Type type) {
27  std::string message;
28  llvm::raw_string_ostream os(message);
29  os << "neither the scoping op nor the type class provide data layout "
30  "information for "
31  << type;
32  llvm::report_fatal_error(Twine(message));
33 }
34 
35 /// Returns the bitwidth of the index type if specified in the param list.
36 /// Assumes 64-bit index otherwise.
37 static uint64_t getIndexBitwidth(DataLayoutEntryListRef params) {
38  if (params.empty())
39  return 64;
40  auto attr = cast<IntegerAttr>(params.front().getValue());
41  return attr.getValue().getZExtValue();
42 }
43 
44 llvm::TypeSize
47  llvm::TypeSize bits = getDefaultTypeSizeInBits(type, dataLayout, params);
48  return divideCeil(bits, 8);
49 }
50 
51 llvm::TypeSize
53  DataLayoutEntryListRef params) {
54  if (type.isIntOrFloat())
55  return llvm::TypeSize::getFixed(type.getIntOrFloatBitWidth());
56 
57  if (auto ctype = dyn_cast<ComplexType>(type)) {
58  Type et = ctype.getElementType();
59  uint64_t innerAlignment =
60  getDefaultPreferredAlignment(et, dataLayout, params) * 8;
61  llvm::TypeSize innerSize = getDefaultTypeSizeInBits(et, dataLayout, params);
62 
63  // Include padding required to align the imaginary value in the complex
64  // type.
65  return llvm::alignTo(innerSize, innerAlignment) + innerSize;
66  }
67 
68  // Index is an integer of some bitwidth.
69  if (isa<IndexType>(type))
70  return dataLayout.getTypeSizeInBits(
72 
73  // Sizes of vector types are rounded up to those of types with closest
74  // power-of-two number of elements in the innermost dimension. We also assume
75  // there is no bit-packing at the moment element sizes are taken in bytes and
76  // multiplied with 8 bits.
77  // TODO: make this extensible.
78  if (auto vecType = dyn_cast<VectorType>(type)) {
79  uint64_t baseSize = vecType.getNumElements() / vecType.getShape().back() *
80  llvm::PowerOf2Ceil(vecType.getShape().back()) *
81  dataLayout.getTypeSize(vecType.getElementType()) * 8;
82  return llvm::TypeSize::get(baseSize, vecType.isScalable());
83  }
84 
85  if (auto typeInterface = dyn_cast<DataLayoutTypeInterface>(type))
86  return typeInterface.getTypeSizeInBits(dataLayout, params);
87 
89 }
90 
91 static DataLayoutEntryInterface
92 findEntryForIntegerType(IntegerType intType,
94  assert(!params.empty() && "expected non-empty parameter list");
95  std::map<unsigned, DataLayoutEntryInterface> sortedParams;
96  for (DataLayoutEntryInterface entry : params) {
97  sortedParams.insert(std::make_pair(
98  cast<Type>(entry.getKey()).getIntOrFloatBitWidth(), entry));
99  }
100  auto iter = sortedParams.lower_bound(intType.getWidth());
101  if (iter == sortedParams.end())
102  iter = std::prev(iter);
103 
104  return iter->second;
105 }
106 
107 constexpr const static uint64_t kDefaultBitsInByte = 8u;
108 
109 static uint64_t extractABIAlignment(DataLayoutEntryInterface entry) {
110  auto values =
111  cast<DenseIntElementsAttr>(entry.getValue()).getValues<uint64_t>();
112  return static_cast<uint64_t>(*values.begin()) / kDefaultBitsInByte;
113 }
114 
115 static uint64_t
116 getIntegerTypeABIAlignment(IntegerType intType,
118  constexpr uint64_t kDefaultSmallIntAlignment = 4u;
119  constexpr unsigned kSmallIntSize = 64;
120  if (params.empty()) {
121  return intType.getWidth() < kSmallIntSize
122  ? llvm::PowerOf2Ceil(
123  llvm::divideCeil(intType.getWidth(), kDefaultBitsInByte))
124  : kDefaultSmallIntAlignment;
125  }
126 
127  return extractABIAlignment(findEntryForIntegerType(intType, params));
128 }
129 
130 static uint64_t
131 getFloatTypeABIAlignment(FloatType fltType, const DataLayout &dataLayout,
133  assert(params.size() <= 1 && "at most one data layout entry is expected for "
134  "the singleton floating-point type");
135  if (params.empty())
136  return llvm::PowerOf2Ceil(dataLayout.getTypeSize(fltType).getFixedValue());
137  return extractABIAlignment(params[0]);
138 }
139 
141  Type type, const DataLayout &dataLayout,
143  // Natural alignment is the closest power-of-two number above. For scalable
144  // vectors, aligning them to the same as the base vector is sufficient.
145  if (isa<VectorType>(type))
146  return llvm::PowerOf2Ceil(dataLayout.getTypeSize(type).getKnownMinValue());
147 
148  if (auto fltType = dyn_cast<FloatType>(type))
149  return getFloatTypeABIAlignment(fltType, dataLayout, params);
150 
151  // Index is an integer of some bitwidth.
152  if (isa<IndexType>(type))
153  return dataLayout.getTypeABIAlignment(
154  IntegerType::get(type.getContext(), getIndexBitwidth(params)));
155 
156  if (auto intType = dyn_cast<IntegerType>(type))
157  return getIntegerTypeABIAlignment(intType, params);
158 
159  if (auto ctype = dyn_cast<ComplexType>(type))
160  return getDefaultABIAlignment(ctype.getElementType(), dataLayout, params);
161 
162  if (auto typeInterface = dyn_cast<DataLayoutTypeInterface>(type))
163  return typeInterface.getABIAlignment(dataLayout, params);
164 
166 }
167 
168 static uint64_t extractPreferredAlignment(DataLayoutEntryInterface entry) {
169  auto values =
170  cast<DenseIntElementsAttr>(entry.getValue()).getValues<uint64_t>();
171  return *std::next(values.begin(), values.size() - 1) / kDefaultBitsInByte;
172 }
173 
174 static uint64_t
176  const DataLayout &dataLayout,
178  if (params.empty())
179  return llvm::PowerOf2Ceil(dataLayout.getTypeSize(intType).getFixedValue());
180 
181  return extractPreferredAlignment(findEntryForIntegerType(intType, params));
182 }
183 
184 static uint64_t
185 getFloatTypePreferredAlignment(FloatType fltType, const DataLayout &dataLayout,
187  assert(params.size() <= 1 && "at most one data layout entry is expected for "
188  "the singleton floating-point type");
189  if (params.empty())
190  return dataLayout.getTypeABIAlignment(fltType);
191  return extractPreferredAlignment(params[0]);
192 }
193 
195  Type type, const DataLayout &dataLayout,
197  // Preferred alignment is same as natural for floats and vectors.
198  if (isa<VectorType>(type))
199  return dataLayout.getTypeABIAlignment(type);
200 
201  if (auto fltType = dyn_cast<FloatType>(type))
202  return getFloatTypePreferredAlignment(fltType, dataLayout, params);
203 
204  // Preferred alignment is the closest power-of-two number above for integers
205  // (ABI alignment may be smaller).
206  if (auto intType = dyn_cast<IntegerType>(type))
207  return getIntegerTypePreferredAlignment(intType, dataLayout, params);
208 
209  if (isa<IndexType>(type)) {
210  return dataLayout.getTypePreferredAlignment(
211  IntegerType::get(type.getContext(), getIndexBitwidth(params)));
212  }
213 
214  if (auto ctype = dyn_cast<ComplexType>(type))
215  return getDefaultPreferredAlignment(ctype.getElementType(), dataLayout,
216  params);
217 
218  if (auto typeInterface = dyn_cast<DataLayoutTypeInterface>(type))
219  return typeInterface.getPreferredAlignment(dataLayout, params);
220 
222 }
223 
225  Type type, const DataLayout &dataLayout,
227  if (isa<IndexType>(type))
228  return getIndexBitwidth(params);
229 
230  if (auto typeInterface = dyn_cast<DataLayoutTypeInterface>(type))
231  if (std::optional<uint64_t> indexBitwidth =
232  typeInterface.getIndexBitwidth(dataLayout, params))
233  return *indexBitwidth;
234 
235  // Return std::nullopt for all other types, which are assumed to be non
236  // pointer-like types.
237  return std::nullopt;
238 }
239 
240 // Returns the endianness if specified in the given entry. If the entry is empty
241 // the default endianness represented by an empty attribute is returned.
242 Attribute mlir::detail::getDefaultEndianness(DataLayoutEntryInterface entry) {
243  if (entry == DataLayoutEntryInterface())
244  return Attribute();
245 
246  return entry.getValue();
247 }
248 
249 // Returns the default memory space if specified in the given entry. If the
250 // entry is empty the default memory space represented by an empty attribute is
251 // returned.
252 Attribute mlir::detail::getDefaultMemorySpace(DataLayoutEntryInterface entry) {
253  if (!entry)
254  return Attribute();
255 
256  return entry.getValue();
257 }
258 
259 // Returns the memory space used for alloca operations if specified in the
260 // given entry. If the entry is empty the default memory space represented by
261 // an empty attribute is returned.
262 Attribute
263 mlir::detail::getDefaultAllocaMemorySpace(DataLayoutEntryInterface entry) {
264  if (entry == DataLayoutEntryInterface()) {
265  return Attribute();
266  }
267 
268  return entry.getValue();
269 }
270 
271 // Returns the mangling mode if specified in the given entry.
272 // If the entry is empty, an empty attribute is returned.
273 Attribute mlir::detail::getDefaultManglingMode(DataLayoutEntryInterface entry) {
274  if (entry == DataLayoutEntryInterface())
275  return Attribute();
276 
277  return entry.getValue();
278 }
279 
280 // Returns the memory space used for the program memory space. if
281 // specified in the given entry. If the entry is empty the default
282 // memory space represented by an empty attribute is returned.
283 Attribute
284 mlir::detail::getDefaultProgramMemorySpace(DataLayoutEntryInterface entry) {
285  if (entry == DataLayoutEntryInterface()) {
286  return Attribute();
287  }
288 
289  return entry.getValue();
290 }
291 
292 // Returns the memory space used for global the global memory space. if
293 // specified in the given entry. If the entry is empty the default memory
294 // space represented by an empty attribute is returned.
295 Attribute
296 mlir::detail::getDefaultGlobalMemorySpace(DataLayoutEntryInterface entry) {
297  if (entry == DataLayoutEntryInterface()) {
298  return Attribute();
299  }
300 
301  return entry.getValue();
302 }
303 
304 // Returns the stack alignment if specified in the given entry. If the entry is
305 // empty the default alignment zero is returned.
306 uint64_t
307 mlir::detail::getDefaultStackAlignment(DataLayoutEntryInterface entry) {
308  if (entry == DataLayoutEntryInterface())
309  return 0;
310 
311  auto value = cast<IntegerAttr>(entry.getValue());
312  return value.getValue().getZExtValue();
313 }
314 
315 // Returns the function pointer alignment if specified in the given entry. If
316 // the entry is empty the default alignment zero is returned.
318  DataLayoutEntryInterface entry) {
319  if (entry == DataLayoutEntryInterface())
320  return Attribute();
321  return entry.getValue();
322 }
323 
324 // Returns the legal int widths if specified in the given entry. If the entry is
325 // empty the default legal int widths represented by an empty attribute is
326 // returned.
327 Attribute
328 mlir::detail::getDefaultLegalIntWidths(DataLayoutEntryInterface entry) {
329  if (entry == DataLayoutEntryInterface())
330  return Attribute();
331  return entry.getValue();
332 }
333 
334 std::optional<Attribute>
335 mlir::detail::getDevicePropertyValue(DataLayoutEntryInterface entry) {
336  if (entry == DataLayoutEntryInterface())
337  return std::nullopt;
338 
339  return entry.getValue();
340 }
341 
344  TypeID typeID) {
345  return llvm::filter_to_vector<4>(
346  entries, [typeID](DataLayoutEntryInterface entry) {
347  auto type = llvm::dyn_cast_if_present<Type>(entry.getKey());
348  return type && type.getTypeID() == typeID;
349  });
350 }
351 
352 DataLayoutEntryInterface
354  StringAttr id) {
355  const auto *it = llvm::find_if(entries, [id](DataLayoutEntryInterface entry) {
356  if (auto attr = dyn_cast<StringAttr>(entry.getKey()))
357  return attr == id;
358  return false;
359  });
360  return it == entries.end() ? DataLayoutEntryInterface() : *it;
361 }
362 
363 static DataLayoutSpecInterface getSpec(Operation *operation) {
365  .Case<ModuleOp, DataLayoutOpInterface>(
366  [&](auto op) { return op.getDataLayoutSpec(); })
367  .Default([](Operation *) {
368  llvm_unreachable("expected an op with data layout spec");
369  return DataLayoutSpecInterface();
370  });
371 }
372 
373 static TargetSystemSpecInterface getTargetSystemSpec(Operation *operation) {
374  if (operation) {
375  ModuleOp moduleOp = dyn_cast<ModuleOp>(operation);
376  if (!moduleOp)
377  moduleOp = operation->getParentOfType<ModuleOp>();
378  return moduleOp.getTargetSystemSpec();
379  }
380  return TargetSystemSpecInterface();
381 }
382 
383 /// Populates `opsWithLayout` with the list of proper ancestors of `leaf` that
384 /// are either modules or implement the `DataLayoutOpInterface`.
385 static void
388  SmallVectorImpl<Location> *opLocations = nullptr) {
389  if (!leaf)
390  return;
391 
392  for (Operation *parent = leaf->getParentOp(); parent != nullptr;
393  parent = parent->getParentOp()) {
395  .Case<ModuleOp>([&](ModuleOp op) {
396  // Skip top-level module op unless it has a layout. Top-level module
397  // without layout is most likely the one implicitly added by the
398  // parser and it doesn't have location. Top-level null specification
399  // would have had the same effect as not having a specification at all
400  // (using type defaults).
401  if (!op->getParentOp() && !op.getDataLayoutSpec())
402  return;
403  specs.push_back(op.getDataLayoutSpec());
404  if (opLocations)
405  opLocations->push_back(op.getLoc());
406  })
407  .Case<DataLayoutOpInterface>([&](DataLayoutOpInterface op) {
408  specs.push_back(op.getDataLayoutSpec());
409  if (opLocations)
410  opLocations->push_back(op.getLoc());
411  });
412  }
413 }
414 
415 /// Returns a layout spec that is a combination of the layout specs attached
416 /// to the given operation and all its ancestors.
417 static DataLayoutSpecInterface getCombinedDataLayout(Operation *leaf) {
418  if (!leaf)
419  return {};
420 
421  assert((isa<ModuleOp, DataLayoutOpInterface>(leaf)) &&
422  "expected an op with data layout spec");
423 
425  collectParentLayouts(leaf, specs);
426 
427  // Fast track if there are no ancestors.
428  if (specs.empty())
429  return getSpec(leaf);
430 
431  // Create the list of non-null specs (null/missing specs can be safely
432  // ignored) from the outermost to the innermost.
433  auto nonNullSpecs = llvm::filter_to_vector<2>(
434  llvm::reverse(specs),
435  [](DataLayoutSpecInterface iface) { return iface != nullptr; });
436 
437  // Combine the specs using the innermost as anchor.
438  if (DataLayoutSpecInterface current = getSpec(leaf))
439  return current.combineWith(nonNullSpecs);
440  if (nonNullSpecs.empty())
441  return {};
442  return nonNullSpecs.back().combineWith(
443  llvm::ArrayRef(nonNullSpecs).drop_back());
444 }
445 
447  DataLayoutSpecInterface spec = getSpec(op);
448  // The layout specification may be missing and it's fine.
449  if (!spec)
450  return success();
451 
452  if (failed(spec.verifySpec(op->getLoc())))
453  return failure();
454  if (!getCombinedDataLayout(op)) {
456  op->emitError()
457  << "data layout does not combine with layouts of enclosing ops";
459  SmallVector<Location> opLocations;
460  collectParentLayouts(op, specs, &opLocations);
461  for (Location loc : opLocations)
462  diag.attachNote(loc) << "enclosing op with data layout";
463  return diag;
464  }
465  return success();
466 }
467 
468 llvm::TypeSize mlir::detail::divideCeil(llvm::TypeSize numerator,
469  uint64_t denominator) {
470  uint64_t divided =
471  llvm::divideCeil(numerator.getKnownMinValue(), denominator);
472  return llvm::TypeSize::get(divided, numerator.isScalable());
473 }
474 
475 //===----------------------------------------------------------------------===//
476 // DataLayout
477 //===----------------------------------------------------------------------===//
478 
479 template <typename OpTy>
480 void checkMissingLayout(DataLayoutSpecInterface originalLayout, OpTy op) {
481  if (!originalLayout) {
482  assert((!op || !op.getDataLayoutSpec()) &&
483  "could not compute layout information for an op (failed to "
484  "combine attributes?)");
485  }
486 }
487 
489 
490 mlir::DataLayout::DataLayout(DataLayoutOpInterface op)
491  : originalLayout(getCombinedDataLayout(op)),
492  originalTargetSystemDesc(getTargetSystemSpec(op)), scope(op),
493  allocaMemorySpace(std::nullopt), programMemorySpace(std::nullopt),
494  globalMemorySpace(std::nullopt), stackAlignment(std::nullopt) {
495 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
496  checkMissingLayout(originalLayout, op);
497  collectParentLayouts(op, layoutStack);
498 #endif
499 }
500 
502  : originalLayout(getCombinedDataLayout(op)),
503  originalTargetSystemDesc(getTargetSystemSpec(op)), scope(op),
504  allocaMemorySpace(std::nullopt), programMemorySpace(std::nullopt),
505  globalMemorySpace(std::nullopt), stackAlignment(std::nullopt) {
506 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
507  checkMissingLayout(originalLayout, op);
508  collectParentLayouts(op, layoutStack);
509 #endif
510 }
511 
513  // Search the closest parent either being a module operation or implementing
514  // the data layout interface.
515  while (op) {
516  if (auto module = dyn_cast<ModuleOp>(op))
517  return DataLayout(module);
518  if (auto iface = dyn_cast<DataLayoutOpInterface>(op))
519  return DataLayout(iface);
520  op = op->getParentOp();
521  }
522  return DataLayout();
523 }
524 
525 void mlir::DataLayout::checkValid() const {
526 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
528  collectParentLayouts(scope, specs);
529  assert(specs.size() == layoutStack.size() &&
530  "data layout object used, but no longer valid due to the change in "
531  "number of nested layouts");
532  for (auto pair : llvm::zip(specs, layoutStack)) {
533  Attribute newLayout = std::get<0>(pair);
534  Attribute origLayout = std::get<1>(pair);
535  assert(newLayout == origLayout &&
536  "data layout object used, but no longer valid "
537  "due to the change in layout attributes");
538  }
539 #endif
540  assert(((!scope && !this->originalLayout) ||
541  (scope && this->originalLayout == getCombinedDataLayout(scope))) &&
542  "data layout object used, but no longer valid due to the change in "
543  "layout spec");
544 }
545 
546 /// Looks up the value for the given type key in the given cache. If there is no
547 /// such value in the cache, compute it using the given callback and put it in
548 /// the cache before returning.
549 template <typename T>
551  function_ref<T(Type)> compute) {
552  auto it = cache.find(t);
553  if (it != cache.end())
554  return it->second;
555 
556  auto result = cache.try_emplace(t, compute(t));
557  return result.first->second;
558 }
559 
560 llvm::TypeSize mlir::DataLayout::getTypeSize(Type t) const {
561  checkValid();
562  return cachedLookup<llvm::TypeSize>(t, sizes, [&](Type ty) {
563  DataLayoutEntryList list;
564  if (originalLayout)
565  list = originalLayout.getSpecForType(ty.getTypeID());
566  if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
567  return iface.getTypeSize(ty, *this, list);
568  return detail::getDefaultTypeSize(ty, *this, list);
569  });
570 }
571 
572 llvm::TypeSize mlir::DataLayout::getTypeSizeInBits(Type t) const {
573  checkValid();
574  return cachedLookup<llvm::TypeSize>(t, bitsizes, [&](Type ty) {
575  DataLayoutEntryList list;
576  if (originalLayout)
577  list = originalLayout.getSpecForType(ty.getTypeID());
578  if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
579  return iface.getTypeSizeInBits(ty, *this, list);
580  return detail::getDefaultTypeSizeInBits(ty, *this, list);
581  });
582 }
583 
585  checkValid();
586  return cachedLookup<uint64_t>(t, abiAlignments, [&](Type ty) {
587  DataLayoutEntryList list;
588  if (originalLayout)
589  list = originalLayout.getSpecForType(ty.getTypeID());
590  if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
591  return iface.getTypeABIAlignment(ty, *this, list);
592  return detail::getDefaultABIAlignment(ty, *this, list);
593  });
594 }
595 
597  checkValid();
598  return cachedLookup<uint64_t>(t, preferredAlignments, [&](Type ty) {
599  DataLayoutEntryList list;
600  if (originalLayout)
601  list = originalLayout.getSpecForType(ty.getTypeID());
602  if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
603  return iface.getTypePreferredAlignment(ty, *this, list);
604  return detail::getDefaultPreferredAlignment(ty, *this, list);
605  });
606 }
607 
608 std::optional<uint64_t> mlir::DataLayout::getTypeIndexBitwidth(Type t) const {
609  checkValid();
610  return cachedLookup<std::optional<uint64_t>>(t, indexBitwidths, [&](Type ty) {
611  DataLayoutEntryList list;
612  if (originalLayout)
613  list = originalLayout.getSpecForType(ty.getTypeID());
614  if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
615  return iface.getIndexBitwidth(ty, *this, list);
616  return detail::getDefaultIndexBitwidth(ty, *this, list);
617  });
618 }
619 
621  checkValid();
622  if (endianness)
623  return *endianness;
624  DataLayoutEntryInterface entry;
625  if (originalLayout)
626  entry = originalLayout.getSpecForIdentifier(
627  originalLayout.getEndiannessIdentifier(originalLayout.getContext()));
628 
629  if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
630  endianness = iface.getEndianness(entry);
631  else
632  endianness = detail::getDefaultEndianness(entry);
633  return *endianness;
634 }
635 
637  checkValid();
638  if (defaultMemorySpace)
639  return *defaultMemorySpace;
640  DataLayoutEntryInterface entry;
641  if (originalLayout)
642  entry = originalLayout.getSpecForIdentifier(
643  originalLayout.getDefaultMemorySpaceIdentifier(
644  originalLayout.getContext()));
645  if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
646  defaultMemorySpace = iface.getDefaultMemorySpace(entry);
647  else
648  defaultMemorySpace = detail::getDefaultMemorySpace(entry);
649  return *defaultMemorySpace;
650 }
651 
653  checkValid();
654  if (allocaMemorySpace)
655  return *allocaMemorySpace;
656  DataLayoutEntryInterface entry;
657  if (originalLayout)
658  entry = originalLayout.getSpecForIdentifier(
659  originalLayout.getAllocaMemorySpaceIdentifier(
660  originalLayout.getContext()));
661  if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
662  allocaMemorySpace = iface.getAllocaMemorySpace(entry);
663  else
664  allocaMemorySpace = detail::getDefaultAllocaMemorySpace(entry);
665  return *allocaMemorySpace;
666 }
667 
669  checkValid();
670  if (manglingMode)
671  return *manglingMode;
672  DataLayoutEntryInterface entry;
673  if (originalLayout)
674  entry = originalLayout.getSpecForIdentifier(
675  originalLayout.getManglingModeIdentifier(originalLayout.getContext()));
676 
677  if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
678  manglingMode = iface.getManglingMode(entry);
679  else
680  manglingMode = detail::getDefaultManglingMode(entry);
681  return *manglingMode;
682 }
683 
685  checkValid();
686  if (programMemorySpace)
687  return *programMemorySpace;
688  DataLayoutEntryInterface entry;
689  if (originalLayout)
690  entry = originalLayout.getSpecForIdentifier(
691  originalLayout.getProgramMemorySpaceIdentifier(
692  originalLayout.getContext()));
693  if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
694  programMemorySpace = iface.getProgramMemorySpace(entry);
695  else
696  programMemorySpace = detail::getDefaultProgramMemorySpace(entry);
697  return *programMemorySpace;
698 }
699 
701  checkValid();
702  if (globalMemorySpace)
703  return *globalMemorySpace;
704  DataLayoutEntryInterface entry;
705  if (originalLayout)
706  entry = originalLayout.getSpecForIdentifier(
707  originalLayout.getGlobalMemorySpaceIdentifier(
708  originalLayout.getContext()));
709  if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
710  globalMemorySpace = iface.getGlobalMemorySpace(entry);
711  else
712  globalMemorySpace = detail::getDefaultGlobalMemorySpace(entry);
713  return *globalMemorySpace;
714 }
715 
717  checkValid();
718  if (stackAlignment)
719  return *stackAlignment;
720  DataLayoutEntryInterface entry;
721  if (originalLayout)
722  entry = originalLayout.getSpecForIdentifier(
723  originalLayout.getStackAlignmentIdentifier(
724  originalLayout.getContext()));
725  if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
726  stackAlignment = iface.getStackAlignment(entry);
727  else
728  stackAlignment = detail::getDefaultStackAlignment(entry);
729  return *stackAlignment;
730 }
731 
733  checkValid();
734  if (functionPointerAlignment)
735  return *functionPointerAlignment;
736  DataLayoutEntryInterface entry;
737  if (originalLayout)
738  entry = originalLayout.getSpecForIdentifier(
739  originalLayout.getFunctionPointerAlignmentIdentifier(
740  originalLayout.getContext()));
741  if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
742  functionPointerAlignment = iface.getFunctionPointerAlignment(entry);
743  else
744  functionPointerAlignment =
746  return *functionPointerAlignment;
747 }
748 
750  checkValid();
751  if (legalIntWidths)
752  return *legalIntWidths;
753  DataLayoutEntryInterface entry;
754  if (originalLayout)
755  entry = originalLayout.getSpecForIdentifier(
756  originalLayout.getLegalIntWidthsIdentifier(
757  originalLayout.getContext()));
758  if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
759  legalIntWidths = iface.getLegalIntWidths(entry);
760  else
761  legalIntWidths = detail::getDefaultLegalIntWidths(entry);
762  return *legalIntWidths;
763 }
764 
766  TargetSystemSpecInterface::DeviceID deviceID,
767  StringAttr propertyName) const {
768  checkValid();
769  DataLayoutEntryInterface entry;
770  if (originalTargetSystemDesc) {
771  if (std::optional<TargetDeviceSpecInterface> device =
772  originalTargetSystemDesc.getDeviceSpecForDeviceID(deviceID))
773  entry = device->getSpecForIdentifier(propertyName);
774  }
775  // Currently I am not caching the results because we do not return
776  // default values of these properties. Instead if the property is
777  // missing, we return std::nullopt so that the users can resort to
778  // the default value however they want.
779  if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
780  return iface.getDevicePropertyValue(entry);
781  else
782  return detail::getDevicePropertyValue(entry);
783 }
784 
785 //===----------------------------------------------------------------------===//
786 // DataLayoutSpecInterface
787 //===----------------------------------------------------------------------===//
788 
789 void DataLayoutSpecInterface::bucketEntriesByType(
790  llvm::MapVector<TypeID, DataLayoutEntryList> &types,
791  llvm::MapVector<StringAttr, DataLayoutEntryInterface> &ids) {
792  for (DataLayoutEntryInterface entry : getEntries()) {
793  if (auto type = llvm::dyn_cast_if_present<Type>(entry.getKey()))
794  types[type.getTypeID()].push_back(entry);
795  else
796  ids[llvm::cast<StringAttr>(entry.getKey())] = entry;
797  }
798 }
799 
800 LogicalResult mlir::detail::verifyDataLayoutSpec(DataLayoutSpecInterface spec,
801  Location loc) {
802  // First, verify individual entries.
803  for (DataLayoutEntryInterface entry : spec.getEntries())
804  if (failed(entry.verifyEntry(loc)))
805  return failure();
806 
807  // Second, dispatch verifications of entry groups to types or dialects they
808  // are associated with.
809  llvm::MapVector<TypeID, DataLayoutEntryList> types;
810  llvm::MapVector<StringAttr, DataLayoutEntryInterface> ids;
811  spec.bucketEntriesByType(types, ids);
812 
813  for (const auto &kvp : types) {
814  auto sampleType = cast<Type>(kvp.second.front().getKey());
815  if (isa<IndexType>(sampleType)) {
816  assert(kvp.second.size() == 1 &&
817  "expected one data layout entry for non-parametric 'index' type");
818  if (!isa<IntegerAttr>(kvp.second.front().getValue()))
819  return emitError(loc)
820  << "expected integer attribute in the data layout entry for "
821  << sampleType;
822  continue;
823  }
824 
825  if (sampleType.isIntOrFloat()) {
826  for (DataLayoutEntryInterface entry : kvp.second) {
827  auto value = dyn_cast<DenseIntElementsAttr>(entry.getValue());
828  if (!value || !value.getElementType().isSignlessInteger(64)) {
829  emitError(loc) << "expected a dense i64 elements attribute in the "
830  "data layout entry "
831  << entry;
832  return failure();
833  }
834 
835  auto elements = llvm::to_vector<2>(value.getValues<uint64_t>());
836  unsigned numElements = elements.size();
837  if (numElements < 1 || numElements > 2) {
838  emitError(loc) << "expected 1 or 2 elements in the data layout entry "
839  << entry;
840  return failure();
841  }
842 
843  uint64_t abi = elements[0];
844  uint64_t preferred = numElements == 2 ? elements[1] : abi;
845  if (preferred < abi) {
846  emitError(loc)
847  << "preferred alignment is expected to be greater than or equal "
848  "to the abi alignment in data layout entry "
849  << entry;
850  return failure();
851  }
852  }
853  continue;
854  }
855 
856  if (isa<BuiltinDialect>(&sampleType.getDialect()))
857  return emitError(loc) << "unexpected data layout for a built-in type";
858 
859  auto dlType = dyn_cast<DataLayoutTypeInterface>(sampleType);
860  if (!dlType)
861  return emitError(loc)
862  << "data layout specified for a type that does not support it";
863  if (failed(dlType.verifyEntries(kvp.second, loc)))
864  return failure();
865  }
866 
867  for (const auto &kvp : ids) {
868  StringAttr identifier = cast<StringAttr>(kvp.second.getKey());
869  Dialect *dialect = identifier.getReferencedDialect();
870 
871  // Ignore attributes that belong to an unknown dialect, the dialect may
872  // actually implement the relevant interface but we don't know about that.
873  if (!dialect)
874  continue;
875 
876  const auto *iface = dyn_cast<DataLayoutDialectInterface>(dialect);
877  if (!iface) {
878  return emitError(loc)
879  << "the '" << dialect->getNamespace()
880  << "' dialect does not support identifier data layout entries";
881  }
882  if (failed(iface->verifyEntry(kvp.second, loc)))
883  return failure();
884  }
885 
886  return success();
887 }
888 
889 LogicalResult
890 mlir::detail::verifyTargetSystemSpec(TargetSystemSpecInterface spec,
891  Location loc) {
894  for (const auto &entry : spec.getEntries()) {
895  auto targetDeviceSpec =
896  dyn_cast<TargetDeviceSpecInterface>(entry.getValue());
897 
898  if (!targetDeviceSpec)
899  return failure();
900 
901  // First, verify individual target device desc specs.
902  if (failed(targetDeviceSpec.verifyEntry(loc)))
903  return failure();
904 
905  // Check that device IDs are unique across all entries.
906  auto deviceID =
907  llvm::dyn_cast<TargetSystemSpecInterface::DeviceID>(entry.getKey());
908  if (!deviceID)
909  return failure();
910 
911  if (!deviceIDs.insert(deviceID).second) {
912  return failure();
913  }
914 
915  // collect all the keys used by all the target device specs.
916  for (DataLayoutEntryInterface entry : targetDeviceSpec.getEntries()) {
917  if (auto type = llvm::dyn_cast_if_present<Type>(entry.getKey())) {
918  // targetDeviceSpec does not support Type as a key.
919  return failure();
920  } else {
921  deviceDescKeys[cast<StringAttr>(entry.getKey())] = entry;
922  }
923  }
924  }
925 
926  for (const auto &[keyName, keyVal] : deviceDescKeys) {
927  Dialect *dialect = keyName.getReferencedDialect();
928 
929  // Ignore attributes that belong to an unknown dialect, the dialect may
930  // actually implement the relevant interface but we don't know about that.
931  if (!dialect)
932  return failure();
933 
934  const auto *iface = dyn_cast<DataLayoutDialectInterface>(dialect);
935  if (!iface) {
936  return emitError(loc)
937  << "the '" << dialect->getNamespace()
938  << "' dialect does not support identifier data layout entries";
939  }
940  if (failed(iface->verifyEntry(keyVal, loc)))
941  return failure();
942  }
943 
944  return success();
945 }
946 
947 #include "mlir/Interfaces/DataLayoutAttrInterface.cpp.inc"
948 #include "mlir/Interfaces/DataLayoutOpInterface.cpp.inc"
949 #include "mlir/Interfaces/DataLayoutTypeInterface.cpp.inc"
static uint64_t getIntegerTypePreferredAlignment(IntegerType intType, const DataLayout &dataLayout, ArrayRef< DataLayoutEntryInterface > params)
static DataLayoutSpecInterface getCombinedDataLayout(Operation *leaf)
Returns a layout spec that is a combination of the layout specs attached to the given operation and a...
static TargetSystemSpecInterface getTargetSystemSpec(Operation *operation)
constexpr static const uint64_t kDefaultBitsInByte
static uint64_t getIntegerTypeABIAlignment(IntegerType intType, ArrayRef< DataLayoutEntryInterface > params)
static T cachedLookup(Type t, DenseMap< Type, T > &cache, function_ref< T(Type)> compute)
Looks up the value for the given type key in the given cache.
static uint64_t extractPreferredAlignment(DataLayoutEntryInterface entry)
static void collectParentLayouts(Operation *leaf, SmallVectorImpl< DataLayoutSpecInterface > &specs, SmallVectorImpl< Location > *opLocations=nullptr)
Populates opsWithLayout with the list of proper ancestors of leaf that are either modules or implemen...
static uint64_t getFloatTypePreferredAlignment(FloatType fltType, const DataLayout &dataLayout, ArrayRef< DataLayoutEntryInterface > params)
static uint64_t getFloatTypeABIAlignment(FloatType fltType, const DataLayout &dataLayout, ArrayRef< DataLayoutEntryInterface > params)
static DataLayoutSpecInterface getSpec(Operation *operation)
static uint64_t getIndexBitwidth(DataLayoutEntryListRef params)
Returns the bitwidth of the index type if specified in the param list.
static uint64_t extractABIAlignment(DataLayoutEntryInterface entry)
static DataLayoutEntryInterface findEntryForIntegerType(IntegerType intType, ArrayRef< DataLayoutEntryInterface > params)
void checkMissingLayout(DataLayoutSpecInterface originalLayout, OpTy op)
static void reportMissingDataLayout(Type type)
Reports that the given type is missing the data layout information and exits.
static std::string diag(const llvm::Value &value)
Attributes are known-constant values of operations.
Definition: Attributes.h:25
The main mechanism for performing data layout queries.
Attribute getAllocaMemorySpace() const
Returns the memory space used for AllocaOps.
static DataLayout closest(Operation *op)
Returns the layout of the closest parent operation carrying layout info.
std::optional< uint64_t > getTypeIndexBitwidth(Type t) const
Returns the bitwidth that should be used when performing index computations for the given pointer-lik...
llvm::TypeSize getTypeSize(Type t) const
Returns the size of the given type in the current scope.
Attribute getManglingMode() const
Returns the mangling mode.
uint64_t getStackAlignment() const
Returns the natural alignment of the stack in bits.
Attribute getProgramMemorySpace() const
Returns the memory space used for program memory operations.
uint64_t getTypePreferredAlignment(Type t) const
Returns the preferred of the given type in the current scope.
Attribute getFunctionPointerAlignment() const
Returns function pointer alignment.
Attribute getGlobalMemorySpace() const
Returns the memory space used for global operations.
uint64_t getTypeABIAlignment(Type t) const
Returns the required alignment of the given type in the current scope.
llvm::TypeSize getTypeSizeInBits(Type t) const
Returns the size in bits of the given type in the current scope.
Attribute getDefaultMemorySpace() const
Returns the default memory space used for memory operations.
Attribute getEndianness() const
Returns the specified endianness.
Attribute getLegalIntWidths() const
Returns the legal int widths.
std::optional< Attribute > getDevicePropertyValue(TargetSystemSpecInterface::DeviceID, StringAttr propertyName) const
Returns the value of the specified property if the property is defined for the given device ID,...
Dialects are groups of MLIR operations, types and attributes, as well as behavior associated with the...
Definition: Dialect.h:38
StringRef getNamespace() const
Definition: Dialect.h:54
This class represents a diagnostic that is inflight and set to be reported.
Definition: Diagnostics.h:314
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition: Location.h:76
Operation is the basic unit of execution within MLIR.
Definition: Operation.h:88
Location getLoc()
The source location the operation was defined or derived from.
Definition: Operation.h:223
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
Definition: Operation.h:234
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
Definition: Operation.cpp:268
OpTy getParentOfType()
Return the closest surrounding parent operation that is of type 'OpTy'.
Definition: Operation.h:238
This class provides an efficient unique identifier for a specific C++ type.
Definition: TypeID.h:107
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition: Types.h:74
MLIRContext * getContext() const
Return the MLIRContext in which this type was uniqued.
Definition: Types.cpp:35
bool isIntOrFloat() const
Return true if this is an integer (of any signedness) or a float type.
Definition: Types.cpp:116
TypeID getTypeID()
Return a unique identifier for the concrete type.
Definition: Types.h:101
unsigned getIntOrFloatBitWidth() const
Return the bit width of an integer or a float type, assert failure on other types.
Definition: Types.cpp:122
Attribute getDefaultAllocaMemorySpace(DataLayoutEntryInterface entry)
Default handler for alloca memory space request.
Attribute getDefaultProgramMemorySpace(DataLayoutEntryInterface entry)
Default handler for program memory space request.
Attribute getDefaultEndianness(DataLayoutEntryInterface entry)
Default handler for endianness request.
std::optional< uint64_t > getDefaultIndexBitwidth(Type type, const DataLayout &dataLayout, ArrayRef< DataLayoutEntryInterface > params)
Default handler for the index bitwidth request.
DataLayoutEntryList filterEntriesForType(DataLayoutEntryListRef entries, TypeID typeID)
Given a list of data layout entries, returns a new list containing the entries with keys having the g...
LogicalResult verifyTargetSystemSpec(TargetSystemSpecInterface spec, Location loc)
Verifies that a target system desc spec is valid.
std::optional< Attribute > getDevicePropertyValue(DataLayoutEntryInterface entry)
Returns the value of the property from the specified DataLayoutEntry.
Attribute getDefaultManglingMode(DataLayoutEntryInterface entry)
Default handler for mangling mode request.
uint64_t getDefaultABIAlignment(Type type, const DataLayout &dataLayout, ArrayRef< DataLayoutEntryInterface > params)
Default handler for the required alignment request.
Attribute getDefaultLegalIntWidths(DataLayoutEntryInterface entry)
Default handler for the legal int widths request.
llvm::TypeSize getDefaultTypeSize(Type type, const DataLayout &dataLayout, DataLayoutEntryListRef params)
Default handler for the type size request.
llvm::TypeSize getDefaultTypeSizeInBits(Type type, const DataLayout &dataLayout, DataLayoutEntryListRef params)
Default handler for the type size in bits request.
uint64_t getDefaultPreferredAlignment(Type type, const DataLayout &dataLayout, ArrayRef< DataLayoutEntryInterface > params)
Default handler for the preferred alignment request.
llvm::TypeSize divideCeil(llvm::TypeSize numerator, uint64_t denominator)
Divides the known min value of the numerator by the denominator and rounds the result up to the next ...
uint64_t getDefaultStackAlignment(DataLayoutEntryInterface entry)
Default handler for the stack alignment request.
Attribute getDefaultGlobalMemorySpace(DataLayoutEntryInterface entry)
Default handler for global memory space request.
Attribute getDefaultMemorySpace(DataLayoutEntryInterface entry)
Default handler for the default memory space request.
LogicalResult verifyDataLayoutOp(Operation *op)
Verifies that the operation implementing the data layout interface, or a module operation,...
LogicalResult verifyDataLayoutSpec(DataLayoutSpecInterface spec, Location loc)
Verifies that a data layout spec is valid.
Attribute getDefaultFunctionPointerAlignment(DataLayoutEntryInterface entry)
Default handler for the function pointer alignment request.
DataLayoutEntryInterface filterEntryForIdentifier(DataLayoutEntryListRef entries, StringAttr id)
Given a list of data layout entries, returns the entry that has the given identifier as key,...
Include the generated interface declarations.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...