[SampleProfileLoader] Fix integer overflow in generateMDProfMetadata (#90217)
[llvm-project.git] / mlir / lib / Interfaces / DataLayoutInterfaces.cpp
blob15cfb3dbaf74518265e33c0e4d8113aece0ef739
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 //===----------------------------------------------------------------------===//
9 #include "mlir/Interfaces/DataLayoutInterfaces.h"
10 #include "mlir/IR/BuiltinDialect.h"
11 #include "mlir/IR/BuiltinOps.h"
12 #include "mlir/IR/BuiltinTypes.h"
13 #include "mlir/IR/Operation.h"
15 #include "llvm/ADT/TypeSwitch.h"
16 #include "llvm/Support/MathExtras.h"
18 using namespace mlir;
20 //===----------------------------------------------------------------------===//
21 // Default implementations
22 //===----------------------------------------------------------------------===//
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(os.str()));
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();
44 llvm::TypeSize
45 mlir::detail::getDefaultTypeSize(Type type, const DataLayout &dataLayout,
46 ArrayRef<DataLayoutEntryInterface> params) {
47 llvm::TypeSize bits = getDefaultTypeSizeInBits(type, dataLayout, params);
48 return divideCeil(bits, 8);
51 llvm::TypeSize
52 mlir::detail::getDefaultTypeSizeInBits(Type type, const DataLayout &dataLayout,
53 DataLayoutEntryListRef params) {
54 if (isa<IntegerType, FloatType>(type))
55 return llvm::TypeSize::getFixed(type.getIntOrFloatBitWidth());
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);
63 // Include padding required to align the imaginary value in the complex
64 // type.
65 return llvm::alignTo(innerSize, innerAlignment) + innerSize;
68 // Index is an integer of some bitwidth.
69 if (isa<IndexType>(type))
70 return dataLayout.getTypeSizeInBits(
71 IntegerType::get(type.getContext(), getIndexBitwidth(params)));
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());
85 if (auto typeInterface = dyn_cast<DataLayoutTypeInterface>(type))
86 return typeInterface.getTypeSizeInBits(dataLayout, params);
88 reportMissingDataLayout(type);
91 static DataLayoutEntryInterface
92 findEntryForIntegerType(IntegerType intType,
93 ArrayRef<DataLayoutEntryInterface> params) {
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 entry.getKey().get<Type>().getIntOrFloatBitWidth(), entry));
100 auto iter = sortedParams.lower_bound(intType.getWidth());
101 if (iter == sortedParams.end())
102 iter = std::prev(iter);
104 return iter->second;
107 constexpr const static uint64_t kDefaultBitsInByte = 8u;
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;
115 static uint64_t
116 getIntegerTypeABIAlignment(IntegerType intType,
117 ArrayRef<DataLayoutEntryInterface> params) {
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;
127 return extractABIAlignment(findEntryForIntegerType(intType, params));
130 static uint64_t
131 getFloatTypeABIAlignment(FloatType fltType, const DataLayout &dataLayout,
132 ArrayRef<DataLayoutEntryInterface> params) {
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]);
140 uint64_t mlir::detail::getDefaultABIAlignment(
141 Type type, const DataLayout &dataLayout,
142 ArrayRef<DataLayoutEntryInterface> params) {
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());
148 if (auto fltType = dyn_cast<FloatType>(type))
149 return getFloatTypeABIAlignment(fltType, dataLayout, params);
151 // Index is an integer of some bitwidth.
152 if (isa<IndexType>(type))
153 return dataLayout.getTypeABIAlignment(
154 IntegerType::get(type.getContext(), getIndexBitwidth(params)));
156 if (auto intType = dyn_cast<IntegerType>(type))
157 return getIntegerTypeABIAlignment(intType, params);
159 if (auto ctype = dyn_cast<ComplexType>(type))
160 return getDefaultABIAlignment(ctype.getElementType(), dataLayout, params);
162 if (auto typeInterface = dyn_cast<DataLayoutTypeInterface>(type))
163 return typeInterface.getABIAlignment(dataLayout, params);
165 reportMissingDataLayout(type);
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;
174 static uint64_t
175 getIntegerTypePreferredAlignment(IntegerType intType,
176 const DataLayout &dataLayout,
177 ArrayRef<DataLayoutEntryInterface> params) {
178 if (params.empty())
179 return llvm::PowerOf2Ceil(dataLayout.getTypeSize(intType).getFixedValue());
181 return extractPreferredAlignment(findEntryForIntegerType(intType, params));
184 static uint64_t
185 getFloatTypePreferredAlignment(FloatType fltType, const DataLayout &dataLayout,
186 ArrayRef<DataLayoutEntryInterface> params) {
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]);
194 uint64_t mlir::detail::getDefaultPreferredAlignment(
195 Type type, const DataLayout &dataLayout,
196 ArrayRef<DataLayoutEntryInterface> params) {
197 // Preferred alignment is same as natural for floats and vectors.
198 if (isa<VectorType>(type))
199 return dataLayout.getTypeABIAlignment(type);
201 if (auto fltType = dyn_cast<FloatType>(type))
202 return getFloatTypePreferredAlignment(fltType, dataLayout, params);
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);
209 if (isa<IndexType>(type)) {
210 return dataLayout.getTypePreferredAlignment(
211 IntegerType::get(type.getContext(), getIndexBitwidth(params)));
214 if (auto ctype = dyn_cast<ComplexType>(type))
215 return getDefaultPreferredAlignment(ctype.getElementType(), dataLayout,
216 params);
218 if (auto typeInterface = dyn_cast<DataLayoutTypeInterface>(type))
219 return typeInterface.getPreferredAlignment(dataLayout, params);
221 reportMissingDataLayout(type);
224 std::optional<uint64_t> mlir::detail::getDefaultIndexBitwidth(
225 Type type, const DataLayout &dataLayout,
226 ArrayRef<DataLayoutEntryInterface> params) {
227 if (isa<IndexType>(type))
228 return getIndexBitwidth(params);
230 if (auto typeInterface = dyn_cast<DataLayoutTypeInterface>(type))
231 if (std::optional<uint64_t> indexBitwidth =
232 typeInterface.getIndexBitwidth(dataLayout, params))
233 return *indexBitwidth;
235 // Return std::nullopt for all other types, which are assumed to be non
236 // pointer-like types.
237 return std::nullopt;
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();
246 return entry.getValue();
249 // Returns the memory space used for alloca operations if specified in the
250 // given entry. If the entry is empty the default memory space represented by
251 // an empty attribute is returned.
252 Attribute
253 mlir::detail::getDefaultAllocaMemorySpace(DataLayoutEntryInterface entry) {
254 if (entry == DataLayoutEntryInterface()) {
255 return Attribute();
258 return entry.getValue();
261 // Returns the memory space used for the program memory space. if
262 // specified in the given entry. If the entry is empty the default
263 // memory space represented by an empty attribute is returned.
264 Attribute
265 mlir::detail::getDefaultProgramMemorySpace(DataLayoutEntryInterface entry) {
266 if (entry == DataLayoutEntryInterface()) {
267 return Attribute();
270 return entry.getValue();
273 // Returns the memory space used for global the global memory space. if
274 // specified in the given entry. If the entry is empty the default memory
275 // space represented by an empty attribute is returned.
276 Attribute
277 mlir::detail::getDefaultGlobalMemorySpace(DataLayoutEntryInterface entry) {
278 if (entry == DataLayoutEntryInterface()) {
279 return Attribute();
282 return entry.getValue();
285 // Returns the stack alignment if specified in the given entry. If the entry is
286 // empty the default alignment zero is returned.
287 uint64_t
288 mlir::detail::getDefaultStackAlignment(DataLayoutEntryInterface entry) {
289 if (entry == DataLayoutEntryInterface())
290 return 0;
292 auto value = cast<IntegerAttr>(entry.getValue());
293 return value.getValue().getZExtValue();
296 DataLayoutEntryList
297 mlir::detail::filterEntriesForType(DataLayoutEntryListRef entries,
298 TypeID typeID) {
299 return llvm::to_vector<4>(llvm::make_filter_range(
300 entries, [typeID](DataLayoutEntryInterface entry) {
301 auto type = llvm::dyn_cast_if_present<Type>(entry.getKey());
302 return type && type.getTypeID() == typeID;
303 }));
306 DataLayoutEntryInterface
307 mlir::detail::filterEntryForIdentifier(DataLayoutEntryListRef entries,
308 StringAttr id) {
309 const auto *it = llvm::find_if(entries, [id](DataLayoutEntryInterface entry) {
310 if (!entry.getKey().is<StringAttr>())
311 return false;
312 return entry.getKey().get<StringAttr>() == id;
314 return it == entries.end() ? DataLayoutEntryInterface() : *it;
317 static DataLayoutSpecInterface getSpec(Operation *operation) {
318 return llvm::TypeSwitch<Operation *, DataLayoutSpecInterface>(operation)
319 .Case<ModuleOp, DataLayoutOpInterface>(
320 [&](auto op) { return op.getDataLayoutSpec(); })
321 .Default([](Operation *) {
322 llvm_unreachable("expected an op with data layout spec");
323 return DataLayoutSpecInterface();
327 /// Populates `opsWithLayout` with the list of proper ancestors of `leaf` that
328 /// are either modules or implement the `DataLayoutOpInterface`.
329 static void
330 collectParentLayouts(Operation *leaf,
331 SmallVectorImpl<DataLayoutSpecInterface> &specs,
332 SmallVectorImpl<Location> *opLocations = nullptr) {
333 if (!leaf)
334 return;
336 for (Operation *parent = leaf->getParentOp(); parent != nullptr;
337 parent = parent->getParentOp()) {
338 llvm::TypeSwitch<Operation *>(parent)
339 .Case<ModuleOp>([&](ModuleOp op) {
340 // Skip top-level module op unless it has a layout. Top-level module
341 // without layout is most likely the one implicitly added by the
342 // parser and it doesn't have location. Top-level null specification
343 // would have had the same effect as not having a specification at all
344 // (using type defaults).
345 if (!op->getParentOp() && !op.getDataLayoutSpec())
346 return;
347 specs.push_back(op.getDataLayoutSpec());
348 if (opLocations)
349 opLocations->push_back(op.getLoc());
351 .Case<DataLayoutOpInterface>([&](DataLayoutOpInterface op) {
352 specs.push_back(op.getDataLayoutSpec());
353 if (opLocations)
354 opLocations->push_back(op.getLoc());
359 /// Returns a layout spec that is a combination of the layout specs attached
360 /// to the given operation and all its ancestors.
361 static DataLayoutSpecInterface getCombinedDataLayout(Operation *leaf) {
362 if (!leaf)
363 return {};
365 assert((isa<ModuleOp, DataLayoutOpInterface>(leaf)) &&
366 "expected an op with data layout spec");
368 SmallVector<DataLayoutOpInterface> opsWithLayout;
369 SmallVector<DataLayoutSpecInterface> specs;
370 collectParentLayouts(leaf, specs);
372 // Fast track if there are no ancestors.
373 if (specs.empty())
374 return getSpec(leaf);
376 // Create the list of non-null specs (null/missing specs can be safely
377 // ignored) from the outermost to the innermost.
378 auto nonNullSpecs = llvm::to_vector<2>(llvm::make_filter_range(
379 llvm::reverse(specs),
380 [](DataLayoutSpecInterface iface) { return iface != nullptr; }));
382 // Combine the specs using the innermost as anchor.
383 if (DataLayoutSpecInterface current = getSpec(leaf))
384 return current.combineWith(nonNullSpecs);
385 if (nonNullSpecs.empty())
386 return {};
387 return nonNullSpecs.back().combineWith(
388 llvm::ArrayRef(nonNullSpecs).drop_back());
391 LogicalResult mlir::detail::verifyDataLayoutOp(Operation *op) {
392 DataLayoutSpecInterface spec = getSpec(op);
393 // The layout specification may be missing and it's fine.
394 if (!spec)
395 return success();
397 if (failed(spec.verifySpec(op->getLoc())))
398 return failure();
399 if (!getCombinedDataLayout(op)) {
400 InFlightDiagnostic diag =
401 op->emitError()
402 << "data layout does not combine with layouts of enclosing ops";
403 SmallVector<DataLayoutSpecInterface> specs;
404 SmallVector<Location> opLocations;
405 collectParentLayouts(op, specs, &opLocations);
406 for (Location loc : opLocations)
407 diag.attachNote(loc) << "enclosing op with data layout";
408 return diag;
410 return success();
413 llvm::TypeSize mlir::detail::divideCeil(llvm::TypeSize numerator,
414 uint64_t denominator) {
415 uint64_t divided =
416 llvm::divideCeil(numerator.getKnownMinValue(), denominator);
417 return llvm::TypeSize::get(divided, numerator.isScalable());
420 //===----------------------------------------------------------------------===//
421 // DataLayout
422 //===----------------------------------------------------------------------===//
424 template <typename OpTy>
425 void checkMissingLayout(DataLayoutSpecInterface originalLayout, OpTy op) {
426 if (!originalLayout) {
427 assert((!op || !op.getDataLayoutSpec()) &&
428 "could not compute layout information for an op (failed to "
429 "combine attributes?)");
433 mlir::DataLayout::DataLayout() : DataLayout(ModuleOp()) {}
435 mlir::DataLayout::DataLayout(DataLayoutOpInterface op)
436 : originalLayout(getCombinedDataLayout(op)), scope(op),
437 allocaMemorySpace(std::nullopt), programMemorySpace(std::nullopt),
438 globalMemorySpace(std::nullopt), stackAlignment(std::nullopt) {
439 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
440 checkMissingLayout(originalLayout, op);
441 collectParentLayouts(op, layoutStack);
442 #endif
445 mlir::DataLayout::DataLayout(ModuleOp op)
446 : originalLayout(getCombinedDataLayout(op)), scope(op),
447 allocaMemorySpace(std::nullopt), programMemorySpace(std::nullopt),
448 globalMemorySpace(std::nullopt), stackAlignment(std::nullopt) {
449 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
450 checkMissingLayout(originalLayout, op);
451 collectParentLayouts(op, layoutStack);
452 #endif
455 mlir::DataLayout mlir::DataLayout::closest(Operation *op) {
456 // Search the closest parent either being a module operation or implementing
457 // the data layout interface.
458 while (op) {
459 if (auto module = dyn_cast<ModuleOp>(op))
460 return DataLayout(module);
461 if (auto iface = dyn_cast<DataLayoutOpInterface>(op))
462 return DataLayout(iface);
463 op = op->getParentOp();
465 return DataLayout();
468 void mlir::DataLayout::checkValid() const {
469 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
470 SmallVector<DataLayoutSpecInterface> specs;
471 collectParentLayouts(scope, specs);
472 assert(specs.size() == layoutStack.size() &&
473 "data layout object used, but no longer valid due to the change in "
474 "number of nested layouts");
475 for (auto pair : llvm::zip(specs, layoutStack)) {
476 Attribute newLayout = std::get<0>(pair);
477 Attribute origLayout = std::get<1>(pair);
478 assert(newLayout == origLayout &&
479 "data layout object used, but no longer valid "
480 "due to the change in layout attributes");
482 #endif
483 assert(((!scope && !this->originalLayout) ||
484 (scope && this->originalLayout == getCombinedDataLayout(scope))) &&
485 "data layout object used, but no longer valid due to the change in "
486 "layout spec");
489 /// Looks up the value for the given type key in the given cache. If there is no
490 /// such value in the cache, compute it using the given callback and put it in
491 /// the cache before returning.
492 template <typename T>
493 static T cachedLookup(Type t, DenseMap<Type, T> &cache,
494 function_ref<T(Type)> compute) {
495 auto it = cache.find(t);
496 if (it != cache.end())
497 return it->second;
499 auto result = cache.try_emplace(t, compute(t));
500 return result.first->second;
503 llvm::TypeSize mlir::DataLayout::getTypeSize(Type t) const {
504 checkValid();
505 return cachedLookup<llvm::TypeSize>(t, sizes, [&](Type ty) {
506 DataLayoutEntryList list;
507 if (originalLayout)
508 list = originalLayout.getSpecForType(ty.getTypeID());
509 if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
510 return iface.getTypeSize(ty, *this, list);
511 return detail::getDefaultTypeSize(ty, *this, list);
515 llvm::TypeSize mlir::DataLayout::getTypeSizeInBits(Type t) const {
516 checkValid();
517 return cachedLookup<llvm::TypeSize>(t, bitsizes, [&](Type ty) {
518 DataLayoutEntryList list;
519 if (originalLayout)
520 list = originalLayout.getSpecForType(ty.getTypeID());
521 if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
522 return iface.getTypeSizeInBits(ty, *this, list);
523 return detail::getDefaultTypeSizeInBits(ty, *this, list);
527 uint64_t mlir::DataLayout::getTypeABIAlignment(Type t) const {
528 checkValid();
529 return cachedLookup<uint64_t>(t, abiAlignments, [&](Type ty) {
530 DataLayoutEntryList list;
531 if (originalLayout)
532 list = originalLayout.getSpecForType(ty.getTypeID());
533 if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
534 return iface.getTypeABIAlignment(ty, *this, list);
535 return detail::getDefaultABIAlignment(ty, *this, list);
539 uint64_t mlir::DataLayout::getTypePreferredAlignment(Type t) const {
540 checkValid();
541 return cachedLookup<uint64_t>(t, preferredAlignments, [&](Type ty) {
542 DataLayoutEntryList list;
543 if (originalLayout)
544 list = originalLayout.getSpecForType(ty.getTypeID());
545 if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
546 return iface.getTypePreferredAlignment(ty, *this, list);
547 return detail::getDefaultPreferredAlignment(ty, *this, list);
551 std::optional<uint64_t> mlir::DataLayout::getTypeIndexBitwidth(Type t) const {
552 checkValid();
553 return cachedLookup<std::optional<uint64_t>>(t, indexBitwidths, [&](Type ty) {
554 DataLayoutEntryList list;
555 if (originalLayout)
556 list = originalLayout.getSpecForType(ty.getTypeID());
557 if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
558 return iface.getIndexBitwidth(ty, *this, list);
559 return detail::getDefaultIndexBitwidth(ty, *this, list);
563 mlir::Attribute mlir::DataLayout::getEndianness() const {
564 checkValid();
565 if (endianness)
566 return *endianness;
567 DataLayoutEntryInterface entry;
568 if (originalLayout)
569 entry = originalLayout.getSpecForIdentifier(
570 originalLayout.getEndiannessIdentifier(originalLayout.getContext()));
572 if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
573 endianness = iface.getEndianness(entry);
574 else
575 endianness = detail::getDefaultEndianness(entry);
576 return *endianness;
579 mlir::Attribute mlir::DataLayout::getAllocaMemorySpace() const {
580 checkValid();
581 if (allocaMemorySpace)
582 return *allocaMemorySpace;
583 DataLayoutEntryInterface entry;
584 if (originalLayout)
585 entry = originalLayout.getSpecForIdentifier(
586 originalLayout.getAllocaMemorySpaceIdentifier(
587 originalLayout.getContext()));
588 if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
589 allocaMemorySpace = iface.getAllocaMemorySpace(entry);
590 else
591 allocaMemorySpace = detail::getDefaultAllocaMemorySpace(entry);
592 return *allocaMemorySpace;
595 mlir::Attribute mlir::DataLayout::getProgramMemorySpace() const {
596 checkValid();
597 if (programMemorySpace)
598 return *programMemorySpace;
599 DataLayoutEntryInterface entry;
600 if (originalLayout)
601 entry = originalLayout.getSpecForIdentifier(
602 originalLayout.getProgramMemorySpaceIdentifier(
603 originalLayout.getContext()));
604 if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
605 programMemorySpace = iface.getProgramMemorySpace(entry);
606 else
607 programMemorySpace = detail::getDefaultProgramMemorySpace(entry);
608 return *programMemorySpace;
611 mlir::Attribute mlir::DataLayout::getGlobalMemorySpace() const {
612 checkValid();
613 if (globalMemorySpace)
614 return *globalMemorySpace;
615 DataLayoutEntryInterface entry;
616 if (originalLayout)
617 entry = originalLayout.getSpecForIdentifier(
618 originalLayout.getGlobalMemorySpaceIdentifier(
619 originalLayout.getContext()));
620 if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
621 globalMemorySpace = iface.getGlobalMemorySpace(entry);
622 else
623 globalMemorySpace = detail::getDefaultGlobalMemorySpace(entry);
624 return *globalMemorySpace;
627 uint64_t mlir::DataLayout::getStackAlignment() const {
628 checkValid();
629 if (stackAlignment)
630 return *stackAlignment;
631 DataLayoutEntryInterface entry;
632 if (originalLayout)
633 entry = originalLayout.getSpecForIdentifier(
634 originalLayout.getStackAlignmentIdentifier(
635 originalLayout.getContext()));
636 if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
637 stackAlignment = iface.getStackAlignment(entry);
638 else
639 stackAlignment = detail::getDefaultStackAlignment(entry);
640 return *stackAlignment;
643 //===----------------------------------------------------------------------===//
644 // DataLayoutSpecInterface
645 //===----------------------------------------------------------------------===//
647 void DataLayoutSpecInterface::bucketEntriesByType(
648 DenseMap<TypeID, DataLayoutEntryList> &types,
649 DenseMap<StringAttr, DataLayoutEntryInterface> &ids) {
650 for (DataLayoutEntryInterface entry : getEntries()) {
651 if (auto type = llvm::dyn_cast_if_present<Type>(entry.getKey()))
652 types[type.getTypeID()].push_back(entry);
653 else
654 ids[entry.getKey().get<StringAttr>()] = entry;
658 LogicalResult mlir::detail::verifyDataLayoutSpec(DataLayoutSpecInterface spec,
659 Location loc) {
660 // First, verify individual entries.
661 for (DataLayoutEntryInterface entry : spec.getEntries())
662 if (failed(entry.verifyEntry(loc)))
663 return failure();
665 // Second, dispatch verifications of entry groups to types or dialects they
666 // are associated with.
667 DenseMap<TypeID, DataLayoutEntryList> types;
668 DenseMap<StringAttr, DataLayoutEntryInterface> ids;
669 spec.bucketEntriesByType(types, ids);
671 for (const auto &kvp : types) {
672 auto sampleType = kvp.second.front().getKey().get<Type>();
673 if (isa<IndexType>(sampleType)) {
674 assert(kvp.second.size() == 1 &&
675 "expected one data layout entry for non-parametric 'index' type");
676 if (!isa<IntegerAttr>(kvp.second.front().getValue()))
677 return emitError(loc)
678 << "expected integer attribute in the data layout entry for "
679 << sampleType;
680 continue;
683 if (isa<IntegerType, FloatType>(sampleType)) {
684 for (DataLayoutEntryInterface entry : kvp.second) {
685 auto value = dyn_cast<DenseIntElementsAttr>(entry.getValue());
686 if (!value || !value.getElementType().isSignlessInteger(64)) {
687 emitError(loc) << "expected a dense i64 elements attribute in the "
688 "data layout entry "
689 << entry;
690 return failure();
693 auto elements = llvm::to_vector<2>(value.getValues<uint64_t>());
694 unsigned numElements = elements.size();
695 if (numElements < 1 || numElements > 2) {
696 emitError(loc) << "expected 1 or 2 elements in the data layout entry "
697 << entry;
698 return failure();
701 uint64_t abi = elements[0];
702 uint64_t preferred = numElements == 2 ? elements[1] : abi;
703 if (preferred < abi) {
704 emitError(loc)
705 << "preferred alignment is expected to be greater than or equal "
706 "to the abi alignment in data layout entry "
707 << entry;
708 return failure();
711 continue;
714 if (isa<BuiltinDialect>(&sampleType.getDialect()))
715 return emitError(loc) << "unexpected data layout for a built-in type";
717 auto dlType = dyn_cast<DataLayoutTypeInterface>(sampleType);
718 if (!dlType)
719 return emitError(loc)
720 << "data layout specified for a type that does not support it";
721 if (failed(dlType.verifyEntries(kvp.second, loc)))
722 return failure();
725 for (const auto &kvp : ids) {
726 StringAttr identifier = kvp.second.getKey().get<StringAttr>();
727 Dialect *dialect = identifier.getReferencedDialect();
729 // Ignore attributes that belong to an unknown dialect, the dialect may
730 // actually implement the relevant interface but we don't know about that.
731 if (!dialect)
732 continue;
734 const auto *iface = dyn_cast<DataLayoutDialectInterface>(dialect);
735 if (!iface) {
736 return emitError(loc)
737 << "the '" << dialect->getNamespace()
738 << "' dialect does not support identifier data layout entries";
740 if (failed(iface->verifyEntry(kvp.second, loc)))
741 return failure();
744 return success();
747 #include "mlir/Interfaces/DataLayoutAttrInterface.cpp.inc"
748 #include "mlir/Interfaces/DataLayoutOpInterface.cpp.inc"
749 #include "mlir/Interfaces/DataLayoutTypeInterface.cpp.inc"