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(message
));
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();
296 std::optional
<Attribute
>
297 mlir::detail::getDevicePropertyValue(DataLayoutEntryInterface entry
) {
298 if (entry
== DataLayoutEntryInterface())
301 return entry
.getValue();
305 mlir::detail::filterEntriesForType(DataLayoutEntryListRef entries
,
307 return llvm::to_vector
<4>(llvm::make_filter_range(
308 entries
, [typeID
](DataLayoutEntryInterface entry
) {
309 auto type
= llvm::dyn_cast_if_present
<Type
>(entry
.getKey());
310 return type
&& type
.getTypeID() == typeID
;
314 DataLayoutEntryInterface
315 mlir::detail::filterEntryForIdentifier(DataLayoutEntryListRef entries
,
317 const auto *it
= llvm::find_if(entries
, [id
](DataLayoutEntryInterface entry
) {
318 if (!entry
.getKey().is
<StringAttr
>())
320 return entry
.getKey().get
<StringAttr
>() == id
;
322 return it
== entries
.end() ? DataLayoutEntryInterface() : *it
;
325 static DataLayoutSpecInterface
getSpec(Operation
*operation
) {
326 return llvm::TypeSwitch
<Operation
*, DataLayoutSpecInterface
>(operation
)
327 .Case
<ModuleOp
, DataLayoutOpInterface
>(
328 [&](auto op
) { return op
.getDataLayoutSpec(); })
329 .Default([](Operation
*) {
330 llvm_unreachable("expected an op with data layout spec");
331 return DataLayoutSpecInterface();
335 static TargetSystemSpecInterface
getTargetSystemSpec(Operation
*operation
) {
337 ModuleOp moduleOp
= dyn_cast
<ModuleOp
>(operation
);
339 moduleOp
= operation
->getParentOfType
<ModuleOp
>();
340 return moduleOp
.getTargetSystemSpec();
342 return TargetSystemSpecInterface();
345 /// Populates `opsWithLayout` with the list of proper ancestors of `leaf` that
346 /// are either modules or implement the `DataLayoutOpInterface`.
348 collectParentLayouts(Operation
*leaf
,
349 SmallVectorImpl
<DataLayoutSpecInterface
> &specs
,
350 SmallVectorImpl
<Location
> *opLocations
= nullptr) {
354 for (Operation
*parent
= leaf
->getParentOp(); parent
!= nullptr;
355 parent
= parent
->getParentOp()) {
356 llvm::TypeSwitch
<Operation
*>(parent
)
357 .Case
<ModuleOp
>([&](ModuleOp op
) {
358 // Skip top-level module op unless it has a layout. Top-level module
359 // without layout is most likely the one implicitly added by the
360 // parser and it doesn't have location. Top-level null specification
361 // would have had the same effect as not having a specification at all
362 // (using type defaults).
363 if (!op
->getParentOp() && !op
.getDataLayoutSpec())
365 specs
.push_back(op
.getDataLayoutSpec());
367 opLocations
->push_back(op
.getLoc());
369 .Case
<DataLayoutOpInterface
>([&](DataLayoutOpInterface op
) {
370 specs
.push_back(op
.getDataLayoutSpec());
372 opLocations
->push_back(op
.getLoc());
377 /// Returns a layout spec that is a combination of the layout specs attached
378 /// to the given operation and all its ancestors.
379 static DataLayoutSpecInterface
getCombinedDataLayout(Operation
*leaf
) {
383 assert((isa
<ModuleOp
, DataLayoutOpInterface
>(leaf
)) &&
384 "expected an op with data layout spec");
386 SmallVector
<DataLayoutOpInterface
> opsWithLayout
;
387 SmallVector
<DataLayoutSpecInterface
> specs
;
388 collectParentLayouts(leaf
, specs
);
390 // Fast track if there are no ancestors.
392 return getSpec(leaf
);
394 // Create the list of non-null specs (null/missing specs can be safely
395 // ignored) from the outermost to the innermost.
396 auto nonNullSpecs
= llvm::to_vector
<2>(llvm::make_filter_range(
397 llvm::reverse(specs
),
398 [](DataLayoutSpecInterface iface
) { return iface
!= nullptr; }));
400 // Combine the specs using the innermost as anchor.
401 if (DataLayoutSpecInterface current
= getSpec(leaf
))
402 return current
.combineWith(nonNullSpecs
);
403 if (nonNullSpecs
.empty())
405 return nonNullSpecs
.back().combineWith(
406 llvm::ArrayRef(nonNullSpecs
).drop_back());
409 LogicalResult
mlir::detail::verifyDataLayoutOp(Operation
*op
) {
410 DataLayoutSpecInterface spec
= getSpec(op
);
411 // The layout specification may be missing and it's fine.
415 if (failed(spec
.verifySpec(op
->getLoc())))
417 if (!getCombinedDataLayout(op
)) {
418 InFlightDiagnostic diag
=
420 << "data layout does not combine with layouts of enclosing ops";
421 SmallVector
<DataLayoutSpecInterface
> specs
;
422 SmallVector
<Location
> opLocations
;
423 collectParentLayouts(op
, specs
, &opLocations
);
424 for (Location loc
: opLocations
)
425 diag
.attachNote(loc
) << "enclosing op with data layout";
431 llvm::TypeSize
mlir::detail::divideCeil(llvm::TypeSize numerator
,
432 uint64_t denominator
) {
434 llvm::divideCeil(numerator
.getKnownMinValue(), denominator
);
435 return llvm::TypeSize::get(divided
, numerator
.isScalable());
438 //===----------------------------------------------------------------------===//
440 //===----------------------------------------------------------------------===//
442 template <typename OpTy
>
443 void checkMissingLayout(DataLayoutSpecInterface originalLayout
, OpTy op
) {
444 if (!originalLayout
) {
445 assert((!op
|| !op
.getDataLayoutSpec()) &&
446 "could not compute layout information for an op (failed to "
447 "combine attributes?)");
451 mlir::DataLayout::DataLayout() : DataLayout(ModuleOp()) {}
453 mlir::DataLayout::DataLayout(DataLayoutOpInterface op
)
454 : originalLayout(getCombinedDataLayout(op
)),
455 originalTargetSystemDesc(getTargetSystemSpec(op
)), scope(op
),
456 allocaMemorySpace(std::nullopt
), programMemorySpace(std::nullopt
),
457 globalMemorySpace(std::nullopt
), stackAlignment(std::nullopt
) {
458 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
459 checkMissingLayout(originalLayout
, op
);
460 collectParentLayouts(op
, layoutStack
);
464 mlir::DataLayout::DataLayout(ModuleOp op
)
465 : originalLayout(getCombinedDataLayout(op
)),
466 originalTargetSystemDesc(getTargetSystemSpec(op
)), scope(op
),
467 allocaMemorySpace(std::nullopt
), programMemorySpace(std::nullopt
),
468 globalMemorySpace(std::nullopt
), stackAlignment(std::nullopt
) {
469 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
470 checkMissingLayout(originalLayout
, op
);
471 collectParentLayouts(op
, layoutStack
);
475 mlir::DataLayout
mlir::DataLayout::closest(Operation
*op
) {
476 // Search the closest parent either being a module operation or implementing
477 // the data layout interface.
479 if (auto module
= dyn_cast
<ModuleOp
>(op
))
480 return DataLayout(module
);
481 if (auto iface
= dyn_cast
<DataLayoutOpInterface
>(op
))
482 return DataLayout(iface
);
483 op
= op
->getParentOp();
488 void mlir::DataLayout::checkValid() const {
489 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
490 SmallVector
<DataLayoutSpecInterface
> specs
;
491 collectParentLayouts(scope
, specs
);
492 assert(specs
.size() == layoutStack
.size() &&
493 "data layout object used, but no longer valid due to the change in "
494 "number of nested layouts");
495 for (auto pair
: llvm::zip(specs
, layoutStack
)) {
496 Attribute newLayout
= std::get
<0>(pair
);
497 Attribute origLayout
= std::get
<1>(pair
);
498 assert(newLayout
== origLayout
&&
499 "data layout object used, but no longer valid "
500 "due to the change in layout attributes");
503 assert(((!scope
&& !this->originalLayout
) ||
504 (scope
&& this->originalLayout
== getCombinedDataLayout(scope
))) &&
505 "data layout object used, but no longer valid due to the change in "
509 /// Looks up the value for the given type key in the given cache. If there is no
510 /// such value in the cache, compute it using the given callback and put it in
511 /// the cache before returning.
512 template <typename T
>
513 static T
cachedLookup(Type t
, DenseMap
<Type
, T
> &cache
,
514 function_ref
<T(Type
)> compute
) {
515 auto it
= cache
.find(t
);
516 if (it
!= cache
.end())
519 auto result
= cache
.try_emplace(t
, compute(t
));
520 return result
.first
->second
;
523 llvm::TypeSize
mlir::DataLayout::getTypeSize(Type t
) const {
525 return cachedLookup
<llvm::TypeSize
>(t
, sizes
, [&](Type ty
) {
526 DataLayoutEntryList list
;
528 list
= originalLayout
.getSpecForType(ty
.getTypeID());
529 if (auto iface
= dyn_cast_or_null
<DataLayoutOpInterface
>(scope
))
530 return iface
.getTypeSize(ty
, *this, list
);
531 return detail::getDefaultTypeSize(ty
, *this, list
);
535 llvm::TypeSize
mlir::DataLayout::getTypeSizeInBits(Type t
) const {
537 return cachedLookup
<llvm::TypeSize
>(t
, bitsizes
, [&](Type ty
) {
538 DataLayoutEntryList list
;
540 list
= originalLayout
.getSpecForType(ty
.getTypeID());
541 if (auto iface
= dyn_cast_or_null
<DataLayoutOpInterface
>(scope
))
542 return iface
.getTypeSizeInBits(ty
, *this, list
);
543 return detail::getDefaultTypeSizeInBits(ty
, *this, list
);
547 uint64_t mlir::DataLayout::getTypeABIAlignment(Type t
) const {
549 return cachedLookup
<uint64_t>(t
, abiAlignments
, [&](Type ty
) {
550 DataLayoutEntryList list
;
552 list
= originalLayout
.getSpecForType(ty
.getTypeID());
553 if (auto iface
= dyn_cast_or_null
<DataLayoutOpInterface
>(scope
))
554 return iface
.getTypeABIAlignment(ty
, *this, list
);
555 return detail::getDefaultABIAlignment(ty
, *this, list
);
559 uint64_t mlir::DataLayout::getTypePreferredAlignment(Type t
) const {
561 return cachedLookup
<uint64_t>(t
, preferredAlignments
, [&](Type ty
) {
562 DataLayoutEntryList list
;
564 list
= originalLayout
.getSpecForType(ty
.getTypeID());
565 if (auto iface
= dyn_cast_or_null
<DataLayoutOpInterface
>(scope
))
566 return iface
.getTypePreferredAlignment(ty
, *this, list
);
567 return detail::getDefaultPreferredAlignment(ty
, *this, list
);
571 std::optional
<uint64_t> mlir::DataLayout::getTypeIndexBitwidth(Type t
) const {
573 return cachedLookup
<std::optional
<uint64_t>>(t
, indexBitwidths
, [&](Type ty
) {
574 DataLayoutEntryList list
;
576 list
= originalLayout
.getSpecForType(ty
.getTypeID());
577 if (auto iface
= dyn_cast_or_null
<DataLayoutOpInterface
>(scope
))
578 return iface
.getIndexBitwidth(ty
, *this, list
);
579 return detail::getDefaultIndexBitwidth(ty
, *this, list
);
583 mlir::Attribute
mlir::DataLayout::getEndianness() const {
587 DataLayoutEntryInterface entry
;
589 entry
= originalLayout
.getSpecForIdentifier(
590 originalLayout
.getEndiannessIdentifier(originalLayout
.getContext()));
592 if (auto iface
= dyn_cast_or_null
<DataLayoutOpInterface
>(scope
))
593 endianness
= iface
.getEndianness(entry
);
595 endianness
= detail::getDefaultEndianness(entry
);
599 mlir::Attribute
mlir::DataLayout::getAllocaMemorySpace() const {
601 if (allocaMemorySpace
)
602 return *allocaMemorySpace
;
603 DataLayoutEntryInterface entry
;
605 entry
= originalLayout
.getSpecForIdentifier(
606 originalLayout
.getAllocaMemorySpaceIdentifier(
607 originalLayout
.getContext()));
608 if (auto iface
= dyn_cast_or_null
<DataLayoutOpInterface
>(scope
))
609 allocaMemorySpace
= iface
.getAllocaMemorySpace(entry
);
611 allocaMemorySpace
= detail::getDefaultAllocaMemorySpace(entry
);
612 return *allocaMemorySpace
;
615 mlir::Attribute
mlir::DataLayout::getProgramMemorySpace() const {
617 if (programMemorySpace
)
618 return *programMemorySpace
;
619 DataLayoutEntryInterface entry
;
621 entry
= originalLayout
.getSpecForIdentifier(
622 originalLayout
.getProgramMemorySpaceIdentifier(
623 originalLayout
.getContext()));
624 if (auto iface
= dyn_cast_or_null
<DataLayoutOpInterface
>(scope
))
625 programMemorySpace
= iface
.getProgramMemorySpace(entry
);
627 programMemorySpace
= detail::getDefaultProgramMemorySpace(entry
);
628 return *programMemorySpace
;
631 mlir::Attribute
mlir::DataLayout::getGlobalMemorySpace() const {
633 if (globalMemorySpace
)
634 return *globalMemorySpace
;
635 DataLayoutEntryInterface entry
;
637 entry
= originalLayout
.getSpecForIdentifier(
638 originalLayout
.getGlobalMemorySpaceIdentifier(
639 originalLayout
.getContext()));
640 if (auto iface
= dyn_cast_or_null
<DataLayoutOpInterface
>(scope
))
641 globalMemorySpace
= iface
.getGlobalMemorySpace(entry
);
643 globalMemorySpace
= detail::getDefaultGlobalMemorySpace(entry
);
644 return *globalMemorySpace
;
647 uint64_t mlir::DataLayout::getStackAlignment() const {
650 return *stackAlignment
;
651 DataLayoutEntryInterface entry
;
653 entry
= originalLayout
.getSpecForIdentifier(
654 originalLayout
.getStackAlignmentIdentifier(
655 originalLayout
.getContext()));
656 if (auto iface
= dyn_cast_or_null
<DataLayoutOpInterface
>(scope
))
657 stackAlignment
= iface
.getStackAlignment(entry
);
659 stackAlignment
= detail::getDefaultStackAlignment(entry
);
660 return *stackAlignment
;
663 std::optional
<Attribute
> mlir::DataLayout::getDevicePropertyValue(
664 TargetSystemSpecInterface::DeviceID deviceID
,
665 StringAttr propertyName
) const {
667 DataLayoutEntryInterface entry
;
668 if (originalTargetSystemDesc
) {
669 if (std::optional
<TargetDeviceSpecInterface
> device
=
670 originalTargetSystemDesc
.getDeviceSpecForDeviceID(deviceID
))
671 entry
= device
->getSpecForIdentifier(propertyName
);
673 // Currently I am not caching the results because we do not return
674 // default values of these properties. Instead if the property is
675 // missing, we return std::nullopt so that the users can resort to
676 // the default value however they want.
677 if (auto iface
= dyn_cast_or_null
<DataLayoutOpInterface
>(scope
))
678 return iface
.getDevicePropertyValue(entry
);
680 return detail::getDevicePropertyValue(entry
);
683 //===----------------------------------------------------------------------===//
684 // DataLayoutSpecInterface
685 //===----------------------------------------------------------------------===//
687 void DataLayoutSpecInterface::bucketEntriesByType(
688 DenseMap
<TypeID
, DataLayoutEntryList
> &types
,
689 DenseMap
<StringAttr
, DataLayoutEntryInterface
> &ids
) {
690 for (DataLayoutEntryInterface entry
: getEntries()) {
691 if (auto type
= llvm::dyn_cast_if_present
<Type
>(entry
.getKey()))
692 types
[type
.getTypeID()].push_back(entry
);
694 ids
[entry
.getKey().get
<StringAttr
>()] = entry
;
698 LogicalResult
mlir::detail::verifyDataLayoutSpec(DataLayoutSpecInterface spec
,
700 // First, verify individual entries.
701 for (DataLayoutEntryInterface entry
: spec
.getEntries())
702 if (failed(entry
.verifyEntry(loc
)))
705 // Second, dispatch verifications of entry groups to types or dialects they
706 // are associated with.
707 DenseMap
<TypeID
, DataLayoutEntryList
> types
;
708 DenseMap
<StringAttr
, DataLayoutEntryInterface
> ids
;
709 spec
.bucketEntriesByType(types
, ids
);
711 for (const auto &kvp
: types
) {
712 auto sampleType
= kvp
.second
.front().getKey().get
<Type
>();
713 if (isa
<IndexType
>(sampleType
)) {
714 assert(kvp
.second
.size() == 1 &&
715 "expected one data layout entry for non-parametric 'index' type");
716 if (!isa
<IntegerAttr
>(kvp
.second
.front().getValue()))
717 return emitError(loc
)
718 << "expected integer attribute in the data layout entry for "
723 if (isa
<IntegerType
, FloatType
>(sampleType
)) {
724 for (DataLayoutEntryInterface entry
: kvp
.second
) {
725 auto value
= dyn_cast
<DenseIntElementsAttr
>(entry
.getValue());
726 if (!value
|| !value
.getElementType().isSignlessInteger(64)) {
727 emitError(loc
) << "expected a dense i64 elements attribute in the "
733 auto elements
= llvm::to_vector
<2>(value
.getValues
<uint64_t>());
734 unsigned numElements
= elements
.size();
735 if (numElements
< 1 || numElements
> 2) {
736 emitError(loc
) << "expected 1 or 2 elements in the data layout entry "
741 uint64_t abi
= elements
[0];
742 uint64_t preferred
= numElements
== 2 ? elements
[1] : abi
;
743 if (preferred
< abi
) {
745 << "preferred alignment is expected to be greater than or equal "
746 "to the abi alignment in data layout entry "
754 if (isa
<BuiltinDialect
>(&sampleType
.getDialect()))
755 return emitError(loc
) << "unexpected data layout for a built-in type";
757 auto dlType
= dyn_cast
<DataLayoutTypeInterface
>(sampleType
);
759 return emitError(loc
)
760 << "data layout specified for a type that does not support it";
761 if (failed(dlType
.verifyEntries(kvp
.second
, loc
)))
765 for (const auto &kvp
: ids
) {
766 StringAttr identifier
= kvp
.second
.getKey().get
<StringAttr
>();
767 Dialect
*dialect
= identifier
.getReferencedDialect();
769 // Ignore attributes that belong to an unknown dialect, the dialect may
770 // actually implement the relevant interface but we don't know about that.
774 const auto *iface
= dyn_cast
<DataLayoutDialectInterface
>(dialect
);
776 return emitError(loc
)
777 << "the '" << dialect
->getNamespace()
778 << "' dialect does not support identifier data layout entries";
780 if (failed(iface
->verifyEntry(kvp
.second
, loc
)))
788 mlir::detail::verifyTargetSystemSpec(TargetSystemSpecInterface spec
,
790 DenseMap
<StringAttr
, DataLayoutEntryInterface
> deviceDescKeys
;
791 DenseSet
<TargetSystemSpecInterface::DeviceID
> deviceIDs
;
792 for (const auto &entry
: spec
.getEntries()) {
793 auto targetDeviceSpec
=
794 dyn_cast
<TargetDeviceSpecInterface
>(entry
.getValue());
796 if (!targetDeviceSpec
)
799 // First, verify individual target device desc specs.
800 if (failed(targetDeviceSpec
.verifyEntry(loc
)))
803 // Check that device IDs are unique across all entries.
805 llvm::dyn_cast
<TargetSystemSpecInterface::DeviceID
>(entry
.getKey());
809 if (!deviceIDs
.insert(deviceID
).second
) {
813 // collect all the keys used by all the target device specs.
814 for (DataLayoutEntryInterface entry
: targetDeviceSpec
.getEntries()) {
815 if (auto type
= llvm::dyn_cast_if_present
<Type
>(entry
.getKey())) {
816 // targetDeviceSpec does not support Type as a key.
819 deviceDescKeys
[entry
.getKey().get
<StringAttr
>()] = entry
;
824 for (const auto &[keyName
, keyVal
] : deviceDescKeys
) {
825 Dialect
*dialect
= keyName
.getReferencedDialect();
827 // Ignore attributes that belong to an unknown dialect, the dialect may
828 // actually implement the relevant interface but we don't know about that.
832 const auto *iface
= dyn_cast
<DataLayoutDialectInterface
>(dialect
);
834 return emitError(loc
)
835 << "the '" << dialect
->getNamespace()
836 << "' dialect does not support identifier data layout entries";
838 if (failed(iface
->verifyEntry(keyVal
, loc
)))
845 #include "mlir/Interfaces/DataLayoutAttrInterface.cpp.inc"
846 #include "mlir/Interfaces/DataLayoutOpInterface.cpp.inc"
847 #include "mlir/Interfaces/DataLayoutTypeInterface.cpp.inc"