1 //===- DataLayoutInterfaces.cpp - Data Layout Interface Implementation ----===//
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
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"
20 //===----------------------------------------------------------------------===//
21 // Default implementations
22 //===----------------------------------------------------------------------===//
24 /// Reports that the given type is missing the data layout information and
26 [[noreturn
]] static void reportMissingDataLayout(Type type
) {
28 llvm::raw_string_ostream
os(message
);
29 os
<< "neither the scoping op nor the type class provide data layout "
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
) {
40 auto attr
= cast
<IntegerAttr
>(params
.front().getValue());
41 return attr
.getValue().getZExtValue();
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);
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
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
);
107 constexpr const static uint64_t kDefaultBitsInByte
= 8u;
109 static uint64_t extractABIAlignment(DataLayoutEntryInterface entry
) {
111 cast
<DenseIntElementsAttr
>(entry
.getValue()).getValues
<uint64_t>();
112 return static_cast<uint64_t>(*values
.begin()) / kDefaultBitsInByte
;
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
));
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");
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
) {
170 cast
<DenseIntElementsAttr
>(entry
.getValue()).getValues
<uint64_t>();
171 return *std::next(values
.begin(), values
.size() - 1) / kDefaultBitsInByte
;
175 getIntegerTypePreferredAlignment(IntegerType intType
,
176 const DataLayout
&dataLayout
,
177 ArrayRef
<DataLayoutEntryInterface
> params
) {
179 return llvm::PowerOf2Ceil(dataLayout
.getTypeSize(intType
).getFixedValue());
181 return extractPreferredAlignment(findEntryForIntegerType(intType
, params
));
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");
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
,
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.
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())
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.
253 mlir::detail::getDefaultAllocaMemorySpace(DataLayoutEntryInterface entry
) {
254 if (entry
== DataLayoutEntryInterface()) {
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.
265 mlir::detail::getDefaultProgramMemorySpace(DataLayoutEntryInterface entry
) {
266 if (entry
== DataLayoutEntryInterface()) {
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.
277 mlir::detail::getDefaultGlobalMemorySpace(DataLayoutEntryInterface entry
) {
278 if (entry
== DataLayoutEntryInterface()) {
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.
288 mlir::detail::getDefaultStackAlignment(DataLayoutEntryInterface entry
) {
289 if (entry
== DataLayoutEntryInterface())
292 auto value
= cast
<IntegerAttr
>(entry
.getValue());
293 return value
.getValue().getZExtValue();
297 mlir::detail::filterEntriesForType(DataLayoutEntryListRef entries
,
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
;
306 DataLayoutEntryInterface
307 mlir::detail::filterEntryForIdentifier(DataLayoutEntryListRef entries
,
309 const auto *it
= llvm::find_if(entries
, [id
](DataLayoutEntryInterface entry
) {
310 if (!entry
.getKey().is
<StringAttr
>())
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`.
330 collectParentLayouts(Operation
*leaf
,
331 SmallVectorImpl
<DataLayoutSpecInterface
> &specs
,
332 SmallVectorImpl
<Location
> *opLocations
= nullptr) {
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())
347 specs
.push_back(op
.getDataLayoutSpec());
349 opLocations
->push_back(op
.getLoc());
351 .Case
<DataLayoutOpInterface
>([&](DataLayoutOpInterface op
) {
352 specs
.push_back(op
.getDataLayoutSpec());
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
) {
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.
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())
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.
397 if (failed(spec
.verifySpec(op
->getLoc())))
399 if (!getCombinedDataLayout(op
)) {
400 InFlightDiagnostic diag
=
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";
413 llvm::TypeSize
mlir::detail::divideCeil(llvm::TypeSize numerator
,
414 uint64_t denominator
) {
416 llvm::divideCeil(numerator
.getKnownMinValue(), denominator
);
417 return llvm::TypeSize::get(divided
, numerator
.isScalable());
420 //===----------------------------------------------------------------------===//
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
);
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
);
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.
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();
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");
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 "
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())
499 auto result
= cache
.try_emplace(t
, compute(t
));
500 return result
.first
->second
;
503 llvm::TypeSize
mlir::DataLayout::getTypeSize(Type t
) const {
505 return cachedLookup
<llvm::TypeSize
>(t
, sizes
, [&](Type ty
) {
506 DataLayoutEntryList list
;
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 {
517 return cachedLookup
<llvm::TypeSize
>(t
, bitsizes
, [&](Type ty
) {
518 DataLayoutEntryList list
;
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 {
529 return cachedLookup
<uint64_t>(t
, abiAlignments
, [&](Type ty
) {
530 DataLayoutEntryList list
;
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 {
541 return cachedLookup
<uint64_t>(t
, preferredAlignments
, [&](Type ty
) {
542 DataLayoutEntryList list
;
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 {
553 return cachedLookup
<std::optional
<uint64_t>>(t
, indexBitwidths
, [&](Type ty
) {
554 DataLayoutEntryList list
;
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 {
567 DataLayoutEntryInterface entry
;
569 entry
= originalLayout
.getSpecForIdentifier(
570 originalLayout
.getEndiannessIdentifier(originalLayout
.getContext()));
572 if (auto iface
= dyn_cast_or_null
<DataLayoutOpInterface
>(scope
))
573 endianness
= iface
.getEndianness(entry
);
575 endianness
= detail::getDefaultEndianness(entry
);
579 mlir::Attribute
mlir::DataLayout::getAllocaMemorySpace() const {
581 if (allocaMemorySpace
)
582 return *allocaMemorySpace
;
583 DataLayoutEntryInterface entry
;
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
);
591 allocaMemorySpace
= detail::getDefaultAllocaMemorySpace(entry
);
592 return *allocaMemorySpace
;
595 mlir::Attribute
mlir::DataLayout::getProgramMemorySpace() const {
597 if (programMemorySpace
)
598 return *programMemorySpace
;
599 DataLayoutEntryInterface entry
;
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
);
607 programMemorySpace
= detail::getDefaultProgramMemorySpace(entry
);
608 return *programMemorySpace
;
611 mlir::Attribute
mlir::DataLayout::getGlobalMemorySpace() const {
613 if (globalMemorySpace
)
614 return *globalMemorySpace
;
615 DataLayoutEntryInterface entry
;
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
);
623 globalMemorySpace
= detail::getDefaultGlobalMemorySpace(entry
);
624 return *globalMemorySpace
;
627 uint64_t mlir::DataLayout::getStackAlignment() const {
630 return *stackAlignment
;
631 DataLayoutEntryInterface entry
;
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
);
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
);
654 ids
[entry
.getKey().get
<StringAttr
>()] = entry
;
658 LogicalResult
mlir::detail::verifyDataLayoutSpec(DataLayoutSpecInterface spec
,
660 // First, verify individual entries.
661 for (DataLayoutEntryInterface entry
: spec
.getEntries())
662 if (failed(entry
.verifyEntry(loc
)))
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 "
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 "
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 "
701 uint64_t abi
= elements
[0];
702 uint64_t preferred
= numElements
== 2 ? elements
[1] : abi
;
703 if (preferred
< abi
) {
705 << "preferred alignment is expected to be greater than or equal "
706 "to the abi alignment in data layout entry "
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
);
719 return emitError(loc
)
720 << "data layout specified for a type that does not support it";
721 if (failed(dlType
.verifyEntries(kvp
.second
, loc
)))
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.
734 const auto *iface
= dyn_cast
<DataLayoutDialectInterface
>(dialect
);
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
)))
747 #include "mlir/Interfaces/DataLayoutAttrInterface.cpp.inc"
748 #include "mlir/Interfaces/DataLayoutOpInterface.cpp.inc"
749 #include "mlir/Interfaces/DataLayoutTypeInterface.cpp.inc"