xref: /llvm-project/mlir/lib/Interfaces/DataLayoutInterfaces.cpp (revision 9192367ad1af30c59d5b7adc0a099bd7e524e5dd)
13ba14fa0SAlex Zinenko //===- DataLayoutInterfaces.cpp - Data Layout Interface Implementation ----===//
23ba14fa0SAlex Zinenko //
33ba14fa0SAlex Zinenko // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43ba14fa0SAlex Zinenko // See https://llvm.org/LICENSE.txt for license information.
53ba14fa0SAlex Zinenko // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63ba14fa0SAlex Zinenko //
73ba14fa0SAlex Zinenko //===----------------------------------------------------------------------===//
83ba14fa0SAlex Zinenko 
93ba14fa0SAlex Zinenko #include "mlir/Interfaces/DataLayoutInterfaces.h"
103ba14fa0SAlex Zinenko #include "mlir/IR/BuiltinDialect.h"
111916b0e0SAlex Zinenko #include "mlir/IR/BuiltinOps.h"
123ba14fa0SAlex Zinenko #include "mlir/IR/BuiltinTypes.h"
133ba14fa0SAlex Zinenko #include "mlir/IR/Operation.h"
143ba14fa0SAlex Zinenko 
151916b0e0SAlex Zinenko #include "llvm/ADT/TypeSwitch.h"
1631686d13STres Popp #include "llvm/Support/MathExtras.h"
171916b0e0SAlex Zinenko 
183ba14fa0SAlex Zinenko using namespace mlir;
193ba14fa0SAlex Zinenko 
203ba14fa0SAlex Zinenko //===----------------------------------------------------------------------===//
213ba14fa0SAlex Zinenko // Default implementations
223ba14fa0SAlex Zinenko //===----------------------------------------------------------------------===//
233ba14fa0SAlex Zinenko 
243ba14fa0SAlex Zinenko /// Reports that the given type is missing the data layout information and
253ba14fa0SAlex Zinenko /// exits.
26f2026f5dSFangrui Song [[noreturn]] static void reportMissingDataLayout(Type type) {
273ba14fa0SAlex Zinenko   std::string message;
283ba14fa0SAlex Zinenko   llvm::raw_string_ostream os(message);
293ba14fa0SAlex Zinenko   os << "neither the scoping op nor the type class provide data layout "
303ba14fa0SAlex Zinenko         "information for "
313ba14fa0SAlex Zinenko      << type;
32884221edSJOE1994   llvm::report_fatal_error(Twine(message));
333ba14fa0SAlex Zinenko }
343ba14fa0SAlex Zinenko 
35b3386a73SAlex Zinenko /// Returns the bitwidth of the index type if specified in the param list.
36b3386a73SAlex Zinenko /// Assumes 64-bit index otherwise.
378134a8fcSOleksandr "Alex" Zinenko static uint64_t getIndexBitwidth(DataLayoutEntryListRef params) {
38b3386a73SAlex Zinenko   if (params.empty())
39b3386a73SAlex Zinenko     return 64;
405550c821STres Popp   auto attr = cast<IntegerAttr>(params.front().getValue());
41b3386a73SAlex Zinenko   return attr.getValue().getZExtValue();
42b3386a73SAlex Zinenko }
43b3386a73SAlex Zinenko 
448134a8fcSOleksandr "Alex" Zinenko llvm::TypeSize
453ba14fa0SAlex Zinenko mlir::detail::getDefaultTypeSize(Type type, const DataLayout &dataLayout,
463ba14fa0SAlex Zinenko                                  ArrayRef<DataLayoutEntryInterface> params) {
478134a8fcSOleksandr "Alex" Zinenko   llvm::TypeSize bits = getDefaultTypeSizeInBits(type, dataLayout, params);
488134a8fcSOleksandr "Alex" Zinenko   return divideCeil(bits, 8);
49f9cdc61dSAlex Zinenko }
50f9cdc61dSAlex Zinenko 
518134a8fcSOleksandr "Alex" Zinenko llvm::TypeSize
528134a8fcSOleksandr "Alex" Zinenko mlir::detail::getDefaultTypeSizeInBits(Type type, const DataLayout &dataLayout,
53f9cdc61dSAlex Zinenko                                        DataLayoutEntryListRef params) {
545550c821STres Popp   if (isa<IntegerType, FloatType>(type))
5521646789SSander de Smalen     return llvm::TypeSize::getFixed(type.getIntOrFloatBitWidth());
563ba14fa0SAlex Zinenko 
575550c821STres Popp   if (auto ctype = dyn_cast<ComplexType>(type)) {
588134a8fcSOleksandr "Alex" Zinenko     Type et = ctype.getElementType();
598134a8fcSOleksandr "Alex" Zinenko     uint64_t innerAlignment =
6031686d13STres Popp         getDefaultPreferredAlignment(et, dataLayout, params) * 8;
618134a8fcSOleksandr "Alex" Zinenko     llvm::TypeSize innerSize = getDefaultTypeSizeInBits(et, dataLayout, params);
6231686d13STres Popp 
6331686d13STres Popp     // Include padding required to align the imaginary value in the complex
6431686d13STres Popp     // type.
6531686d13STres Popp     return llvm::alignTo(innerSize, innerAlignment) + innerSize;
6631686d13STres Popp   }
6731686d13STres Popp 
68b3386a73SAlex Zinenko   // Index is an integer of some bitwidth.
695550c821STres Popp   if (isa<IndexType>(type))
70b3386a73SAlex Zinenko     return dataLayout.getTypeSizeInBits(
71b3386a73SAlex Zinenko         IntegerType::get(type.getContext(), getIndexBitwidth(params)));
72b3386a73SAlex Zinenko 
733ba14fa0SAlex Zinenko   // Sizes of vector types are rounded up to those of types with closest
74f9cdc61dSAlex Zinenko   // power-of-two number of elements in the innermost dimension. We also assume
75f9cdc61dSAlex Zinenko   // there is no bit-packing at the moment element sizes are taken in bytes and
76f9cdc61dSAlex Zinenko   // multiplied with 8 bits.
773ba14fa0SAlex Zinenko   // TODO: make this extensible.
78df411fbaSChristian Ulmann   if (auto vecType = dyn_cast<VectorType>(type)) {
79df411fbaSChristian Ulmann     uint64_t baseSize = vecType.getNumElements() / vecType.getShape().back() *
80f9cdc61dSAlex Zinenko                         llvm::PowerOf2Ceil(vecType.getShape().back()) *
81f9cdc61dSAlex Zinenko                         dataLayout.getTypeSize(vecType.getElementType()) * 8;
82df411fbaSChristian Ulmann     return llvm::TypeSize::get(baseSize, vecType.isScalable());
83df411fbaSChristian Ulmann   }
843ba14fa0SAlex Zinenko 
855550c821STres Popp   if (auto typeInterface = dyn_cast<DataLayoutTypeInterface>(type))
86f9cdc61dSAlex Zinenko     return typeInterface.getTypeSizeInBits(dataLayout, params);
873ba14fa0SAlex Zinenko 
883ba14fa0SAlex Zinenko   reportMissingDataLayout(type);
893ba14fa0SAlex Zinenko }
903ba14fa0SAlex Zinenko 
91f64170aaSAlex Zinenko static DataLayoutEntryInterface
92f64170aaSAlex Zinenko findEntryForIntegerType(IntegerType intType,
93f64170aaSAlex Zinenko                         ArrayRef<DataLayoutEntryInterface> params) {
94f64170aaSAlex Zinenko   assert(!params.empty() && "expected non-empty parameter list");
95f64170aaSAlex Zinenko   std::map<unsigned, DataLayoutEntryInterface> sortedParams;
96f64170aaSAlex Zinenko   for (DataLayoutEntryInterface entry : params) {
97f64170aaSAlex Zinenko     sortedParams.insert(std::make_pair(
98*9192367aSKazu Hirata         cast<Type>(entry.getKey()).getIntOrFloatBitWidth(), entry));
99f64170aaSAlex Zinenko   }
100f64170aaSAlex Zinenko   auto iter = sortedParams.lower_bound(intType.getWidth());
101f64170aaSAlex Zinenko   if (iter == sortedParams.end())
102f64170aaSAlex Zinenko     iter = std::prev(iter);
103f64170aaSAlex Zinenko 
104f64170aaSAlex Zinenko   return iter->second;
105f64170aaSAlex Zinenko }
106f64170aaSAlex Zinenko 
1078134a8fcSOleksandr "Alex" Zinenko constexpr const static uint64_t kDefaultBitsInByte = 8u;
1088134a8fcSOleksandr "Alex" Zinenko 
1098134a8fcSOleksandr "Alex" Zinenko static uint64_t extractABIAlignment(DataLayoutEntryInterface entry) {
110f64170aaSAlex Zinenko   auto values =
1118134a8fcSOleksandr "Alex" Zinenko       cast<DenseIntElementsAttr>(entry.getValue()).getValues<uint64_t>();
1128134a8fcSOleksandr "Alex" Zinenko   return static_cast<uint64_t>(*values.begin()) / kDefaultBitsInByte;
113f64170aaSAlex Zinenko }
114f64170aaSAlex Zinenko 
1158134a8fcSOleksandr "Alex" Zinenko static uint64_t
116f64170aaSAlex Zinenko getIntegerTypeABIAlignment(IntegerType intType,
117f64170aaSAlex Zinenko                            ArrayRef<DataLayoutEntryInterface> params) {
1188134a8fcSOleksandr "Alex" Zinenko   constexpr uint64_t kDefaultSmallIntAlignment = 4u;
1198134a8fcSOleksandr "Alex" Zinenko   constexpr unsigned kSmallIntSize = 64;
120f64170aaSAlex Zinenko   if (params.empty()) {
1218134a8fcSOleksandr "Alex" Zinenko     return intType.getWidth() < kSmallIntSize
1228134a8fcSOleksandr "Alex" Zinenko                ? llvm::PowerOf2Ceil(
1238134a8fcSOleksandr "Alex" Zinenko                      llvm::divideCeil(intType.getWidth(), kDefaultBitsInByte))
1248134a8fcSOleksandr "Alex" Zinenko                : kDefaultSmallIntAlignment;
125f64170aaSAlex Zinenko   }
126f64170aaSAlex Zinenko 
127f64170aaSAlex Zinenko   return extractABIAlignment(findEntryForIntegerType(intType, params));
128f64170aaSAlex Zinenko }
129f64170aaSAlex Zinenko 
1308134a8fcSOleksandr "Alex" Zinenko static uint64_t
131f64170aaSAlex Zinenko getFloatTypeABIAlignment(FloatType fltType, const DataLayout &dataLayout,
132f64170aaSAlex Zinenko                          ArrayRef<DataLayoutEntryInterface> params) {
133f64170aaSAlex Zinenko   assert(params.size() <= 1 && "at most one data layout entry is expected for "
134f64170aaSAlex Zinenko                                "the singleton floating-point type");
135f64170aaSAlex Zinenko   if (params.empty())
1368134a8fcSOleksandr "Alex" Zinenko     return llvm::PowerOf2Ceil(dataLayout.getTypeSize(fltType).getFixedValue());
137f64170aaSAlex Zinenko   return extractABIAlignment(params[0]);
138f64170aaSAlex Zinenko }
139f64170aaSAlex Zinenko 
1408134a8fcSOleksandr "Alex" Zinenko uint64_t mlir::detail::getDefaultABIAlignment(
1413ba14fa0SAlex Zinenko     Type type, const DataLayout &dataLayout,
1423ba14fa0SAlex Zinenko     ArrayRef<DataLayoutEntryInterface> params) {
143df411fbaSChristian Ulmann   // Natural alignment is the closest power-of-two number above. For scalable
144df411fbaSChristian Ulmann   // vectors, aligning them to the same as the base vector is sufficient.
1455550c821STres Popp   if (isa<VectorType>(type))
146df411fbaSChristian Ulmann     return llvm::PowerOf2Ceil(dataLayout.getTypeSize(type).getKnownMinValue());
1473ba14fa0SAlex Zinenko 
1485550c821STres Popp   if (auto fltType = dyn_cast<FloatType>(type))
149f64170aaSAlex Zinenko     return getFloatTypeABIAlignment(fltType, dataLayout, params);
150f64170aaSAlex Zinenko 
151b3386a73SAlex Zinenko   // Index is an integer of some bitwidth.
1525550c821STres Popp   if (isa<IndexType>(type))
153b3386a73SAlex Zinenko     return dataLayout.getTypeABIAlignment(
154b3386a73SAlex Zinenko         IntegerType::get(type.getContext(), getIndexBitwidth(params)));
155b3386a73SAlex Zinenko 
1565550c821STres Popp   if (auto intType = dyn_cast<IntegerType>(type))
157f64170aaSAlex Zinenko     return getIntegerTypeABIAlignment(intType, params);
1583ba14fa0SAlex Zinenko 
1595550c821STres Popp   if (auto ctype = dyn_cast<ComplexType>(type))
16031686d13STres Popp     return getDefaultABIAlignment(ctype.getElementType(), dataLayout, params);
16131686d13STres Popp 
1625550c821STres Popp   if (auto typeInterface = dyn_cast<DataLayoutTypeInterface>(type))
1633ba14fa0SAlex Zinenko     return typeInterface.getABIAlignment(dataLayout, params);
1643ba14fa0SAlex Zinenko 
1653ba14fa0SAlex Zinenko   reportMissingDataLayout(type);
1663ba14fa0SAlex Zinenko }
1673ba14fa0SAlex Zinenko 
1688134a8fcSOleksandr "Alex" Zinenko static uint64_t extractPreferredAlignment(DataLayoutEntryInterface entry) {
169f64170aaSAlex Zinenko   auto values =
1708134a8fcSOleksandr "Alex" Zinenko       cast<DenseIntElementsAttr>(entry.getValue()).getValues<uint64_t>();
1718134a8fcSOleksandr "Alex" Zinenko   return *std::next(values.begin(), values.size() - 1) / kDefaultBitsInByte;
172f64170aaSAlex Zinenko }
173f64170aaSAlex Zinenko 
1748134a8fcSOleksandr "Alex" Zinenko static uint64_t
175f64170aaSAlex Zinenko getIntegerTypePreferredAlignment(IntegerType intType,
176f64170aaSAlex Zinenko                                  const DataLayout &dataLayout,
177f64170aaSAlex Zinenko                                  ArrayRef<DataLayoutEntryInterface> params) {
178f64170aaSAlex Zinenko   if (params.empty())
1798134a8fcSOleksandr "Alex" Zinenko     return llvm::PowerOf2Ceil(dataLayout.getTypeSize(intType).getFixedValue());
180f64170aaSAlex Zinenko 
181f64170aaSAlex Zinenko   return extractPreferredAlignment(findEntryForIntegerType(intType, params));
182f64170aaSAlex Zinenko }
183f64170aaSAlex Zinenko 
1848134a8fcSOleksandr "Alex" Zinenko static uint64_t
185f64170aaSAlex Zinenko getFloatTypePreferredAlignment(FloatType fltType, const DataLayout &dataLayout,
186f64170aaSAlex Zinenko                                ArrayRef<DataLayoutEntryInterface> params) {
187f64170aaSAlex Zinenko   assert(params.size() <= 1 && "at most one data layout entry is expected for "
188f64170aaSAlex Zinenko                                "the singleton floating-point type");
189f64170aaSAlex Zinenko   if (params.empty())
190f64170aaSAlex Zinenko     return dataLayout.getTypeABIAlignment(fltType);
191f64170aaSAlex Zinenko   return extractPreferredAlignment(params[0]);
192f64170aaSAlex Zinenko }
193f64170aaSAlex Zinenko 
1948134a8fcSOleksandr "Alex" Zinenko uint64_t mlir::detail::getDefaultPreferredAlignment(
1953ba14fa0SAlex Zinenko     Type type, const DataLayout &dataLayout,
1963ba14fa0SAlex Zinenko     ArrayRef<DataLayoutEntryInterface> params) {
1973ba14fa0SAlex Zinenko   // Preferred alignment is same as natural for floats and vectors.
1985550c821STres Popp   if (isa<VectorType>(type))
1993ba14fa0SAlex Zinenko     return dataLayout.getTypeABIAlignment(type);
2003ba14fa0SAlex Zinenko 
2015550c821STres Popp   if (auto fltType = dyn_cast<FloatType>(type))
202f64170aaSAlex Zinenko     return getFloatTypePreferredAlignment(fltType, dataLayout, params);
203f64170aaSAlex Zinenko 
204f64170aaSAlex Zinenko   // Preferred alignment is the closest power-of-two number above for integers
2053ba14fa0SAlex Zinenko   // (ABI alignment may be smaller).
2065550c821STres Popp   if (auto intType = dyn_cast<IntegerType>(type))
207f64170aaSAlex Zinenko     return getIntegerTypePreferredAlignment(intType, dataLayout, params);
208f64170aaSAlex Zinenko 
2095550c821STres Popp   if (isa<IndexType>(type)) {
210f64170aaSAlex Zinenko     return dataLayout.getTypePreferredAlignment(
211f64170aaSAlex Zinenko         IntegerType::get(type.getContext(), getIndexBitwidth(params)));
212f64170aaSAlex Zinenko   }
2133ba14fa0SAlex Zinenko 
2145550c821STres Popp   if (auto ctype = dyn_cast<ComplexType>(type))
21531686d13STres Popp     return getDefaultPreferredAlignment(ctype.getElementType(), dataLayout,
21631686d13STres Popp                                         params);
21731686d13STres Popp 
2185550c821STres Popp   if (auto typeInterface = dyn_cast<DataLayoutTypeInterface>(type))
2193ba14fa0SAlex Zinenko     return typeInterface.getPreferredAlignment(dataLayout, params);
2203ba14fa0SAlex Zinenko 
2213ba14fa0SAlex Zinenko   reportMissingDataLayout(type);
2223ba14fa0SAlex Zinenko }
2233ba14fa0SAlex Zinenko 
224adda5973STobias Gysi std::optional<uint64_t> mlir::detail::getDefaultIndexBitwidth(
225adda5973STobias Gysi     Type type, const DataLayout &dataLayout,
226adda5973STobias Gysi     ArrayRef<DataLayoutEntryInterface> params) {
227adda5973STobias Gysi   if (isa<IndexType>(type))
228adda5973STobias Gysi     return getIndexBitwidth(params);
229adda5973STobias Gysi 
230adda5973STobias Gysi   if (auto typeInterface = dyn_cast<DataLayoutTypeInterface>(type))
231adda5973STobias Gysi     if (std::optional<uint64_t> indexBitwidth =
232adda5973STobias Gysi             typeInterface.getIndexBitwidth(dataLayout, params))
233adda5973STobias Gysi       return *indexBitwidth;
234adda5973STobias Gysi 
235adda5973STobias Gysi   // Return std::nullopt for all other types, which are assumed to be non
236adda5973STobias Gysi   // pointer-like types.
237adda5973STobias Gysi   return std::nullopt;
238adda5973STobias Gysi }
239adda5973STobias Gysi 
240a2acf313SChristian Ulmann // Returns the endianness if specified in the given entry. If the entry is empty
241a2acf313SChristian Ulmann // the default endianness represented by an empty attribute is returned.
242a2acf313SChristian Ulmann Attribute mlir::detail::getDefaultEndianness(DataLayoutEntryInterface entry) {
243a2acf313SChristian Ulmann   if (entry == DataLayoutEntryInterface())
244a2acf313SChristian Ulmann     return Attribute();
245a2acf313SChristian Ulmann 
246a2acf313SChristian Ulmann   return entry.getValue();
247a2acf313SChristian Ulmann }
248a2acf313SChristian Ulmann 
249adda5973STobias Gysi // Returns the memory space used for alloca operations if specified in the
250382eb7c2SJan Sjodin // given entry. If the entry is empty the default memory space represented by
251382eb7c2SJan Sjodin // an empty attribute is returned.
252382eb7c2SJan Sjodin Attribute
253382eb7c2SJan Sjodin mlir::detail::getDefaultAllocaMemorySpace(DataLayoutEntryInterface entry) {
254382eb7c2SJan Sjodin   if (entry == DataLayoutEntryInterface()) {
255382eb7c2SJan Sjodin     return Attribute();
256382eb7c2SJan Sjodin   }
257382eb7c2SJan Sjodin 
258382eb7c2SJan Sjodin   return entry.getValue();
259382eb7c2SJan Sjodin }
260382eb7c2SJan Sjodin 
261c1ed45a2Sagozillon // Returns the memory space used for the program memory space.  if
262c1ed45a2Sagozillon // specified in the given entry. If the entry is empty the default
263c1ed45a2Sagozillon // memory space represented by an empty attribute is returned.
264c1ed45a2Sagozillon Attribute
265c1ed45a2Sagozillon mlir::detail::getDefaultProgramMemorySpace(DataLayoutEntryInterface entry) {
266c1ed45a2Sagozillon   if (entry == DataLayoutEntryInterface()) {
267c1ed45a2Sagozillon     return Attribute();
268c1ed45a2Sagozillon   }
269c1ed45a2Sagozillon 
270c1ed45a2Sagozillon   return entry.getValue();
271c1ed45a2Sagozillon }
272c1ed45a2Sagozillon 
273c1ed45a2Sagozillon // Returns the memory space used for global the global memory space. if
274c1ed45a2Sagozillon // specified in the given entry. If the entry is empty the default memory
275c1ed45a2Sagozillon // space represented by an empty attribute is returned.
276c1ed45a2Sagozillon Attribute
277c1ed45a2Sagozillon mlir::detail::getDefaultGlobalMemorySpace(DataLayoutEntryInterface entry) {
278c1ed45a2Sagozillon   if (entry == DataLayoutEntryInterface()) {
279c1ed45a2Sagozillon     return Attribute();
280c1ed45a2Sagozillon   }
281c1ed45a2Sagozillon 
282c1ed45a2Sagozillon   return entry.getValue();
283c1ed45a2Sagozillon }
284c1ed45a2Sagozillon 
2859d69bca1STobias Gysi // Returns the stack alignment if specified in the given entry. If the entry is
2869d69bca1STobias Gysi // empty the default alignment zero is returned.
2878134a8fcSOleksandr "Alex" Zinenko uint64_t
2889d69bca1STobias Gysi mlir::detail::getDefaultStackAlignment(DataLayoutEntryInterface entry) {
2899d69bca1STobias Gysi   if (entry == DataLayoutEntryInterface())
2909d69bca1STobias Gysi     return 0;
2919d69bca1STobias Gysi 
2925550c821STres Popp   auto value = cast<IntegerAttr>(entry.getValue());
2939d69bca1STobias Gysi   return value.getValue().getZExtValue();
2949d69bca1STobias Gysi }
2959d69bca1STobias Gysi 
296bdeee9b1SNiranjan Hasabnis std::optional<Attribute>
297bdeee9b1SNiranjan Hasabnis mlir::detail::getDevicePropertyValue(DataLayoutEntryInterface entry) {
298abd95342SNiranjan Hasabnis   if (entry == DataLayoutEntryInterface())
299abd95342SNiranjan Hasabnis     return std::nullopt;
300abd95342SNiranjan Hasabnis 
301bdeee9b1SNiranjan Hasabnis   return entry.getValue();
302abd95342SNiranjan Hasabnis }
303abd95342SNiranjan Hasabnis 
3043ba14fa0SAlex Zinenko DataLayoutEntryList
3053ba14fa0SAlex Zinenko mlir::detail::filterEntriesForType(DataLayoutEntryListRef entries,
3063ba14fa0SAlex Zinenko                                    TypeID typeID) {
307f4d75863SJakub Kuderski   return llvm::filter_to_vector<4>(
3083ba14fa0SAlex Zinenko       entries, [typeID](DataLayoutEntryInterface entry) {
30968f58812STres Popp         auto type = llvm::dyn_cast_if_present<Type>(entry.getKey());
3103ba14fa0SAlex Zinenko         return type && type.getTypeID() == typeID;
311f4d75863SJakub Kuderski       });
3123ba14fa0SAlex Zinenko }
3133ba14fa0SAlex Zinenko 
3143ba14fa0SAlex Zinenko DataLayoutEntryInterface
3153ba14fa0SAlex Zinenko mlir::detail::filterEntryForIdentifier(DataLayoutEntryListRef entries,
316195730a6SRiver Riddle                                        StringAttr id) {
3173ba14fa0SAlex Zinenko   const auto *it = llvm::find_if(entries, [id](DataLayoutEntryInterface entry) {
318*9192367aSKazu Hirata     if (auto attr = dyn_cast<StringAttr>(entry.getKey()))
319*9192367aSKazu Hirata       return attr == id;
3203ba14fa0SAlex Zinenko     return false;
3213ba14fa0SAlex Zinenko   });
3223ba14fa0SAlex Zinenko   return it == entries.end() ? DataLayoutEntryInterface() : *it;
3233ba14fa0SAlex Zinenko }
3243ba14fa0SAlex Zinenko 
3251916b0e0SAlex Zinenko static DataLayoutSpecInterface getSpec(Operation *operation) {
3261916b0e0SAlex Zinenko   return llvm::TypeSwitch<Operation *, DataLayoutSpecInterface>(operation)
3271916b0e0SAlex Zinenko       .Case<ModuleOp, DataLayoutOpInterface>(
3281916b0e0SAlex Zinenko           [&](auto op) { return op.getDataLayoutSpec(); })
3291916b0e0SAlex Zinenko       .Default([](Operation *) {
3301916b0e0SAlex Zinenko         llvm_unreachable("expected an op with data layout spec");
3311916b0e0SAlex Zinenko         return DataLayoutSpecInterface();
3321916b0e0SAlex Zinenko       });
3331916b0e0SAlex Zinenko }
3341916b0e0SAlex Zinenko 
335abd95342SNiranjan Hasabnis static TargetSystemSpecInterface getTargetSystemSpec(Operation *operation) {
336abd95342SNiranjan Hasabnis   if (operation) {
337abd95342SNiranjan Hasabnis     ModuleOp moduleOp = dyn_cast<ModuleOp>(operation);
338abd95342SNiranjan Hasabnis     if (!moduleOp)
339abd95342SNiranjan Hasabnis       moduleOp = operation->getParentOfType<ModuleOp>();
340abd95342SNiranjan Hasabnis     return moduleOp.getTargetSystemSpec();
341abd95342SNiranjan Hasabnis   }
342abd95342SNiranjan Hasabnis   return TargetSystemSpecInterface();
343abd95342SNiranjan Hasabnis }
344abd95342SNiranjan Hasabnis 
3453ba14fa0SAlex Zinenko /// Populates `opsWithLayout` with the list of proper ancestors of `leaf` that
3461916b0e0SAlex Zinenko /// are either modules or implement the `DataLayoutOpInterface`.
3471916b0e0SAlex Zinenko static void
3481916b0e0SAlex Zinenko collectParentLayouts(Operation *leaf,
3491916b0e0SAlex Zinenko                      SmallVectorImpl<DataLayoutSpecInterface> &specs,
3501916b0e0SAlex Zinenko                      SmallVectorImpl<Location> *opLocations = nullptr) {
3513ba14fa0SAlex Zinenko   if (!leaf)
3523ba14fa0SAlex Zinenko     return;
3533ba14fa0SAlex Zinenko 
3541916b0e0SAlex Zinenko   for (Operation *parent = leaf->getParentOp(); parent != nullptr;
3551916b0e0SAlex Zinenko        parent = parent->getParentOp()) {
3561916b0e0SAlex Zinenko     llvm::TypeSwitch<Operation *>(parent)
3571916b0e0SAlex Zinenko         .Case<ModuleOp>([&](ModuleOp op) {
3581916b0e0SAlex Zinenko           // Skip top-level module op unless it has a layout. Top-level module
3591916b0e0SAlex Zinenko           // without layout is most likely the one implicitly added by the
3601916b0e0SAlex Zinenko           // parser and it doesn't have location. Top-level null specification
3611916b0e0SAlex Zinenko           // would have had the same effect as not having a specification at all
3621916b0e0SAlex Zinenko           // (using type defaults).
3631916b0e0SAlex Zinenko           if (!op->getParentOp() && !op.getDataLayoutSpec())
3641916b0e0SAlex Zinenko             return;
3651916b0e0SAlex Zinenko           specs.push_back(op.getDataLayoutSpec());
3661916b0e0SAlex Zinenko           if (opLocations)
3671916b0e0SAlex Zinenko             opLocations->push_back(op.getLoc());
3681916b0e0SAlex Zinenko         })
3691916b0e0SAlex Zinenko         .Case<DataLayoutOpInterface>([&](DataLayoutOpInterface op) {
3701916b0e0SAlex Zinenko           specs.push_back(op.getDataLayoutSpec());
3711916b0e0SAlex Zinenko           if (opLocations)
3721916b0e0SAlex Zinenko             opLocations->push_back(op.getLoc());
3731916b0e0SAlex Zinenko         });
3743ba14fa0SAlex Zinenko   }
3753ba14fa0SAlex Zinenko }
3763ba14fa0SAlex Zinenko 
3773ba14fa0SAlex Zinenko /// Returns a layout spec that is a combination of the layout specs attached
3783ba14fa0SAlex Zinenko /// to the given operation and all its ancestors.
3791916b0e0SAlex Zinenko static DataLayoutSpecInterface getCombinedDataLayout(Operation *leaf) {
3803ba14fa0SAlex Zinenko   if (!leaf)
3813ba14fa0SAlex Zinenko     return {};
3823ba14fa0SAlex Zinenko 
3831916b0e0SAlex Zinenko   assert((isa<ModuleOp, DataLayoutOpInterface>(leaf)) &&
3841916b0e0SAlex Zinenko          "expected an op with data layout spec");
3851916b0e0SAlex Zinenko 
3863ba14fa0SAlex Zinenko   SmallVector<DataLayoutOpInterface> opsWithLayout;
3871916b0e0SAlex Zinenko   SmallVector<DataLayoutSpecInterface> specs;
3881916b0e0SAlex Zinenko   collectParentLayouts(leaf, specs);
3893ba14fa0SAlex Zinenko 
3903ba14fa0SAlex Zinenko   // Fast track if there are no ancestors.
3911916b0e0SAlex Zinenko   if (specs.empty())
3921916b0e0SAlex Zinenko     return getSpec(leaf);
3933ba14fa0SAlex Zinenko 
3943ba14fa0SAlex Zinenko   // Create the list of non-null specs (null/missing specs can be safely
3953ba14fa0SAlex Zinenko   // ignored) from the outermost to the innermost.
396f4d75863SJakub Kuderski   auto nonNullSpecs = llvm::filter_to_vector<2>(
3971916b0e0SAlex Zinenko       llvm::reverse(specs),
398f4d75863SJakub Kuderski       [](DataLayoutSpecInterface iface) { return iface != nullptr; });
3993ba14fa0SAlex Zinenko 
4003ba14fa0SAlex Zinenko   // Combine the specs using the innermost as anchor.
4011916b0e0SAlex Zinenko   if (DataLayoutSpecInterface current = getSpec(leaf))
4021916b0e0SAlex Zinenko     return current.combineWith(nonNullSpecs);
4031916b0e0SAlex Zinenko   if (nonNullSpecs.empty())
4043ba14fa0SAlex Zinenko     return {};
4051916b0e0SAlex Zinenko   return nonNullSpecs.back().combineWith(
406984b800aSserge-sans-paille       llvm::ArrayRef(nonNullSpecs).drop_back());
4073ba14fa0SAlex Zinenko }
4083ba14fa0SAlex Zinenko 
4091916b0e0SAlex Zinenko LogicalResult mlir::detail::verifyDataLayoutOp(Operation *op) {
4101916b0e0SAlex Zinenko   DataLayoutSpecInterface spec = getSpec(op);
4113ba14fa0SAlex Zinenko   // The layout specification may be missing and it's fine.
4123ba14fa0SAlex Zinenko   if (!spec)
4133ba14fa0SAlex Zinenko     return success();
4143ba14fa0SAlex Zinenko 
4151916b0e0SAlex Zinenko   if (failed(spec.verifySpec(op->getLoc())))
4163ba14fa0SAlex Zinenko     return failure();
4173ba14fa0SAlex Zinenko   if (!getCombinedDataLayout(op)) {
4183ba14fa0SAlex Zinenko     InFlightDiagnostic diag =
4191916b0e0SAlex Zinenko         op->emitError()
4201916b0e0SAlex Zinenko         << "data layout does not combine with layouts of enclosing ops";
4211916b0e0SAlex Zinenko     SmallVector<DataLayoutSpecInterface> specs;
4221916b0e0SAlex Zinenko     SmallVector<Location> opLocations;
4231916b0e0SAlex Zinenko     collectParentLayouts(op, specs, &opLocations);
4241916b0e0SAlex Zinenko     for (Location loc : opLocations)
4251916b0e0SAlex Zinenko       diag.attachNote(loc) << "enclosing op with data layout";
4263ba14fa0SAlex Zinenko     return diag;
4273ba14fa0SAlex Zinenko   }
4283ba14fa0SAlex Zinenko   return success();
4293ba14fa0SAlex Zinenko }
4303ba14fa0SAlex Zinenko 
4318134a8fcSOleksandr "Alex" Zinenko llvm::TypeSize mlir::detail::divideCeil(llvm::TypeSize numerator,
4328134a8fcSOleksandr "Alex" Zinenko                                         uint64_t denominator) {
4338134a8fcSOleksandr "Alex" Zinenko   uint64_t divided =
4348134a8fcSOleksandr "Alex" Zinenko       llvm::divideCeil(numerator.getKnownMinValue(), denominator);
4358134a8fcSOleksandr "Alex" Zinenko   return llvm::TypeSize::get(divided, numerator.isScalable());
4368134a8fcSOleksandr "Alex" Zinenko }
4378134a8fcSOleksandr "Alex" Zinenko 
4383ba14fa0SAlex Zinenko //===----------------------------------------------------------------------===//
4393ba14fa0SAlex Zinenko // DataLayout
4403ba14fa0SAlex Zinenko //===----------------------------------------------------------------------===//
4413ba14fa0SAlex Zinenko 
4421916b0e0SAlex Zinenko template <typename OpTy>
4431916b0e0SAlex Zinenko void checkMissingLayout(DataLayoutSpecInterface originalLayout, OpTy op) {
4443ba14fa0SAlex Zinenko   if (!originalLayout) {
4453ba14fa0SAlex Zinenko     assert((!op || !op.getDataLayoutSpec()) &&
4463ba14fa0SAlex Zinenko            "could not compute layout information for an op (failed to "
4473ba14fa0SAlex Zinenko            "combine attributes?)");
4483ba14fa0SAlex Zinenko   }
4491916b0e0SAlex Zinenko }
4503ba14fa0SAlex Zinenko 
451b3386a73SAlex Zinenko mlir::DataLayout::DataLayout() : DataLayout(ModuleOp()) {}
452b3386a73SAlex Zinenko 
4531916b0e0SAlex Zinenko mlir::DataLayout::DataLayout(DataLayoutOpInterface op)
454abd95342SNiranjan Hasabnis     : originalLayout(getCombinedDataLayout(op)),
455abd95342SNiranjan Hasabnis       originalTargetSystemDesc(getTargetSystemSpec(op)), scope(op),
456c1ed45a2Sagozillon       allocaMemorySpace(std::nullopt), programMemorySpace(std::nullopt),
457c1ed45a2Sagozillon       globalMemorySpace(std::nullopt), stackAlignment(std::nullopt) {
45897335ad1SMarkus Böck #if LLVM_ENABLE_ABI_BREAKING_CHECKS
4591916b0e0SAlex Zinenko   checkMissingLayout(originalLayout, op);
4601916b0e0SAlex Zinenko   collectParentLayouts(op, layoutStack);
4611916b0e0SAlex Zinenko #endif
4621916b0e0SAlex Zinenko }
4631916b0e0SAlex Zinenko 
4641916b0e0SAlex Zinenko mlir::DataLayout::DataLayout(ModuleOp op)
465abd95342SNiranjan Hasabnis     : originalLayout(getCombinedDataLayout(op)),
466abd95342SNiranjan Hasabnis       originalTargetSystemDesc(getTargetSystemSpec(op)), scope(op),
467c1ed45a2Sagozillon       allocaMemorySpace(std::nullopt), programMemorySpace(std::nullopt),
468c1ed45a2Sagozillon       globalMemorySpace(std::nullopt), stackAlignment(std::nullopt) {
46997335ad1SMarkus Böck #if LLVM_ENABLE_ABI_BREAKING_CHECKS
4701916b0e0SAlex Zinenko   checkMissingLayout(originalLayout, op);
4711916b0e0SAlex Zinenko   collectParentLayouts(op, layoutStack);
4723ba14fa0SAlex Zinenko #endif
4733ba14fa0SAlex Zinenko }
4743ba14fa0SAlex Zinenko 
475b614ada0STobias Gysi mlir::DataLayout mlir::DataLayout::closest(Operation *op) {
476b614ada0STobias Gysi   // Search the closest parent either being a module operation or implementing
477b614ada0STobias Gysi   // the data layout interface.
478b614ada0STobias Gysi   while (op) {
479b614ada0STobias Gysi     if (auto module = dyn_cast<ModuleOp>(op))
480b614ada0STobias Gysi       return DataLayout(module);
481b614ada0STobias Gysi     if (auto iface = dyn_cast<DataLayoutOpInterface>(op))
482b614ada0STobias Gysi       return DataLayout(iface);
483b614ada0STobias Gysi     op = op->getParentOp();
484b614ada0STobias Gysi   }
485b614ada0STobias Gysi   return DataLayout();
486b614ada0STobias Gysi }
487b614ada0STobias Gysi 
4883ba14fa0SAlex Zinenko void mlir::DataLayout::checkValid() const {
48997335ad1SMarkus Böck #if LLVM_ENABLE_ABI_BREAKING_CHECKS
4901916b0e0SAlex Zinenko   SmallVector<DataLayoutSpecInterface> specs;
4911916b0e0SAlex Zinenko   collectParentLayouts(scope, specs);
4921916b0e0SAlex Zinenko   assert(specs.size() == layoutStack.size() &&
4933ba14fa0SAlex Zinenko          "data layout object used, but no longer valid due to the change in "
4943ba14fa0SAlex Zinenko          "number of nested layouts");
4951916b0e0SAlex Zinenko   for (auto pair : llvm::zip(specs, layoutStack)) {
4961916b0e0SAlex Zinenko     Attribute newLayout = std::get<0>(pair);
4973ba14fa0SAlex Zinenko     Attribute origLayout = std::get<1>(pair);
4983ba14fa0SAlex Zinenko     assert(newLayout == origLayout &&
4993ba14fa0SAlex Zinenko            "data layout object used, but no longer valid "
5003ba14fa0SAlex Zinenko            "due to the change in layout attributes");
5013ba14fa0SAlex Zinenko   }
5023ba14fa0SAlex Zinenko #endif
5033ba14fa0SAlex Zinenko   assert(((!scope && !this->originalLayout) ||
5043ba14fa0SAlex Zinenko           (scope && this->originalLayout == getCombinedDataLayout(scope))) &&
5053ba14fa0SAlex Zinenko          "data layout object used, but no longer valid due to the change in "
5063ba14fa0SAlex Zinenko          "layout spec");
5073ba14fa0SAlex Zinenko }
5083ba14fa0SAlex Zinenko 
5093ba14fa0SAlex Zinenko /// Looks up the value for the given type key in the given cache. If there is no
5103ba14fa0SAlex Zinenko /// such value in the cache, compute it using the given callback and put it in
5113ba14fa0SAlex Zinenko /// the cache before returning.
5128134a8fcSOleksandr "Alex" Zinenko template <typename T>
5138134a8fcSOleksandr "Alex" Zinenko static T cachedLookup(Type t, DenseMap<Type, T> &cache,
5148134a8fcSOleksandr "Alex" Zinenko                       function_ref<T(Type)> compute) {
5153ba14fa0SAlex Zinenko   auto it = cache.find(t);
5163ba14fa0SAlex Zinenko   if (it != cache.end())
5173ba14fa0SAlex Zinenko     return it->second;
5183ba14fa0SAlex Zinenko 
5193ba14fa0SAlex Zinenko   auto result = cache.try_emplace(t, compute(t));
5203ba14fa0SAlex Zinenko   return result.first->second;
5213ba14fa0SAlex Zinenko }
5223ba14fa0SAlex Zinenko 
5238134a8fcSOleksandr "Alex" Zinenko llvm::TypeSize mlir::DataLayout::getTypeSize(Type t) const {
5243ba14fa0SAlex Zinenko   checkValid();
5258134a8fcSOleksandr "Alex" Zinenko   return cachedLookup<llvm::TypeSize>(t, sizes, [&](Type ty) {
526842d2435SAlex Zinenko     DataLayoutEntryList list;
527842d2435SAlex Zinenko     if (originalLayout)
528842d2435SAlex Zinenko       list = originalLayout.getSpecForType(ty.getTypeID());
529842d2435SAlex Zinenko     if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
5301916b0e0SAlex Zinenko       return iface.getTypeSize(ty, *this, list);
5311916b0e0SAlex Zinenko     return detail::getDefaultTypeSize(ty, *this, list);
5323ba14fa0SAlex Zinenko   });
5333ba14fa0SAlex Zinenko }
5343ba14fa0SAlex Zinenko 
5358134a8fcSOleksandr "Alex" Zinenko llvm::TypeSize mlir::DataLayout::getTypeSizeInBits(Type t) const {
536f9cdc61dSAlex Zinenko   checkValid();
5378134a8fcSOleksandr "Alex" Zinenko   return cachedLookup<llvm::TypeSize>(t, bitsizes, [&](Type ty) {
538842d2435SAlex Zinenko     DataLayoutEntryList list;
539842d2435SAlex Zinenko     if (originalLayout)
540842d2435SAlex Zinenko       list = originalLayout.getSpecForType(ty.getTypeID());
541842d2435SAlex Zinenko     if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
542f9cdc61dSAlex Zinenko       return iface.getTypeSizeInBits(ty, *this, list);
543f9cdc61dSAlex Zinenko     return detail::getDefaultTypeSizeInBits(ty, *this, list);
544f9cdc61dSAlex Zinenko   });
545f9cdc61dSAlex Zinenko }
546f9cdc61dSAlex Zinenko 
5478134a8fcSOleksandr "Alex" Zinenko uint64_t mlir::DataLayout::getTypeABIAlignment(Type t) const {
5483ba14fa0SAlex Zinenko   checkValid();
5498134a8fcSOleksandr "Alex" Zinenko   return cachedLookup<uint64_t>(t, abiAlignments, [&](Type ty) {
550842d2435SAlex Zinenko     DataLayoutEntryList list;
551842d2435SAlex Zinenko     if (originalLayout)
552842d2435SAlex Zinenko       list = originalLayout.getSpecForType(ty.getTypeID());
553842d2435SAlex Zinenko     if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
5541916b0e0SAlex Zinenko       return iface.getTypeABIAlignment(ty, *this, list);
5551916b0e0SAlex Zinenko     return detail::getDefaultABIAlignment(ty, *this, list);
5563ba14fa0SAlex Zinenko   });
5573ba14fa0SAlex Zinenko }
5583ba14fa0SAlex Zinenko 
5598134a8fcSOleksandr "Alex" Zinenko uint64_t mlir::DataLayout::getTypePreferredAlignment(Type t) const {
5603ba14fa0SAlex Zinenko   checkValid();
5618134a8fcSOleksandr "Alex" Zinenko   return cachedLookup<uint64_t>(t, preferredAlignments, [&](Type ty) {
562842d2435SAlex Zinenko     DataLayoutEntryList list;
563842d2435SAlex Zinenko     if (originalLayout)
564842d2435SAlex Zinenko       list = originalLayout.getSpecForType(ty.getTypeID());
565842d2435SAlex Zinenko     if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
5661916b0e0SAlex Zinenko       return iface.getTypePreferredAlignment(ty, *this, list);
5671916b0e0SAlex Zinenko     return detail::getDefaultPreferredAlignment(ty, *this, list);
5683ba14fa0SAlex Zinenko   });
5693ba14fa0SAlex Zinenko }
5703ba14fa0SAlex Zinenko 
571adda5973STobias Gysi std::optional<uint64_t> mlir::DataLayout::getTypeIndexBitwidth(Type t) const {
572adda5973STobias Gysi   checkValid();
573adda5973STobias Gysi   return cachedLookup<std::optional<uint64_t>>(t, indexBitwidths, [&](Type ty) {
574adda5973STobias Gysi     DataLayoutEntryList list;
575adda5973STobias Gysi     if (originalLayout)
576adda5973STobias Gysi       list = originalLayout.getSpecForType(ty.getTypeID());
577adda5973STobias Gysi     if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
578adda5973STobias Gysi       return iface.getIndexBitwidth(ty, *this, list);
579adda5973STobias Gysi     return detail::getDefaultIndexBitwidth(ty, *this, list);
580adda5973STobias Gysi   });
581adda5973STobias Gysi }
582adda5973STobias Gysi 
583a2acf313SChristian Ulmann mlir::Attribute mlir::DataLayout::getEndianness() const {
584a2acf313SChristian Ulmann   checkValid();
585a2acf313SChristian Ulmann   if (endianness)
586a2acf313SChristian Ulmann     return *endianness;
587a2acf313SChristian Ulmann   DataLayoutEntryInterface entry;
588a2acf313SChristian Ulmann   if (originalLayout)
589a2acf313SChristian Ulmann     entry = originalLayout.getSpecForIdentifier(
590a2acf313SChristian Ulmann         originalLayout.getEndiannessIdentifier(originalLayout.getContext()));
591a2acf313SChristian Ulmann 
592a2acf313SChristian Ulmann   if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
593a2acf313SChristian Ulmann     endianness = iface.getEndianness(entry);
594a2acf313SChristian Ulmann   else
595a2acf313SChristian Ulmann     endianness = detail::getDefaultEndianness(entry);
596a2acf313SChristian Ulmann   return *endianness;
597a2acf313SChristian Ulmann }
598a2acf313SChristian Ulmann 
599382eb7c2SJan Sjodin mlir::Attribute mlir::DataLayout::getAllocaMemorySpace() const {
600382eb7c2SJan Sjodin   checkValid();
601382eb7c2SJan Sjodin   if (allocaMemorySpace)
602382eb7c2SJan Sjodin     return *allocaMemorySpace;
603382eb7c2SJan Sjodin   DataLayoutEntryInterface entry;
604382eb7c2SJan Sjodin   if (originalLayout)
605382eb7c2SJan Sjodin     entry = originalLayout.getSpecForIdentifier(
60611ee125cSJohannes de Fine Licht         originalLayout.getAllocaMemorySpaceIdentifier(
60711ee125cSJohannes de Fine Licht             originalLayout.getContext()));
608382eb7c2SJan Sjodin   if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
609382eb7c2SJan Sjodin     allocaMemorySpace = iface.getAllocaMemorySpace(entry);
610382eb7c2SJan Sjodin   else
611382eb7c2SJan Sjodin     allocaMemorySpace = detail::getDefaultAllocaMemorySpace(entry);
612382eb7c2SJan Sjodin   return *allocaMemorySpace;
613382eb7c2SJan Sjodin }
614382eb7c2SJan Sjodin 
615c1ed45a2Sagozillon mlir::Attribute mlir::DataLayout::getProgramMemorySpace() const {
616c1ed45a2Sagozillon   checkValid();
617c1ed45a2Sagozillon   if (programMemorySpace)
618c1ed45a2Sagozillon     return *programMemorySpace;
619c1ed45a2Sagozillon   DataLayoutEntryInterface entry;
620c1ed45a2Sagozillon   if (originalLayout)
621c1ed45a2Sagozillon     entry = originalLayout.getSpecForIdentifier(
622c1ed45a2Sagozillon         originalLayout.getProgramMemorySpaceIdentifier(
623c1ed45a2Sagozillon             originalLayout.getContext()));
624c1ed45a2Sagozillon   if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
625c1ed45a2Sagozillon     programMemorySpace = iface.getProgramMemorySpace(entry);
626c1ed45a2Sagozillon   else
627c1ed45a2Sagozillon     programMemorySpace = detail::getDefaultProgramMemorySpace(entry);
628c1ed45a2Sagozillon   return *programMemorySpace;
629c1ed45a2Sagozillon }
630c1ed45a2Sagozillon 
631c1ed45a2Sagozillon mlir::Attribute mlir::DataLayout::getGlobalMemorySpace() const {
632c1ed45a2Sagozillon   checkValid();
633c1ed45a2Sagozillon   if (globalMemorySpace)
634c1ed45a2Sagozillon     return *globalMemorySpace;
635c1ed45a2Sagozillon   DataLayoutEntryInterface entry;
636c1ed45a2Sagozillon   if (originalLayout)
637c1ed45a2Sagozillon     entry = originalLayout.getSpecForIdentifier(
638c1ed45a2Sagozillon         originalLayout.getGlobalMemorySpaceIdentifier(
639c1ed45a2Sagozillon             originalLayout.getContext()));
640c1ed45a2Sagozillon   if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
641c1ed45a2Sagozillon     globalMemorySpace = iface.getGlobalMemorySpace(entry);
642c1ed45a2Sagozillon   else
643c1ed45a2Sagozillon     globalMemorySpace = detail::getDefaultGlobalMemorySpace(entry);
644c1ed45a2Sagozillon   return *globalMemorySpace;
645c1ed45a2Sagozillon }
646c1ed45a2Sagozillon 
6478134a8fcSOleksandr "Alex" Zinenko uint64_t mlir::DataLayout::getStackAlignment() const {
6489d69bca1STobias Gysi   checkValid();
6499d69bca1STobias Gysi   if (stackAlignment)
6509d69bca1STobias Gysi     return *stackAlignment;
6519d69bca1STobias Gysi   DataLayoutEntryInterface entry;
6529d69bca1STobias Gysi   if (originalLayout)
6539d69bca1STobias Gysi     entry = originalLayout.getSpecForIdentifier(
65411ee125cSJohannes de Fine Licht         originalLayout.getStackAlignmentIdentifier(
65511ee125cSJohannes de Fine Licht             originalLayout.getContext()));
6569d69bca1STobias Gysi   if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
6579d69bca1STobias Gysi     stackAlignment = iface.getStackAlignment(entry);
6589d69bca1STobias Gysi   else
6599d69bca1STobias Gysi     stackAlignment = detail::getDefaultStackAlignment(entry);
6609d69bca1STobias Gysi   return *stackAlignment;
6619d69bca1STobias Gysi }
6629d69bca1STobias Gysi 
663bdeee9b1SNiranjan Hasabnis std::optional<Attribute> mlir::DataLayout::getDevicePropertyValue(
664abd95342SNiranjan Hasabnis     TargetSystemSpecInterface::DeviceID deviceID,
665abd95342SNiranjan Hasabnis     StringAttr propertyName) const {
666abd95342SNiranjan Hasabnis   checkValid();
667abd95342SNiranjan Hasabnis   DataLayoutEntryInterface entry;
668abd95342SNiranjan Hasabnis   if (originalTargetSystemDesc) {
669abd95342SNiranjan Hasabnis     if (std::optional<TargetDeviceSpecInterface> device =
670abd95342SNiranjan Hasabnis             originalTargetSystemDesc.getDeviceSpecForDeviceID(deviceID))
671abd95342SNiranjan Hasabnis       entry = device->getSpecForIdentifier(propertyName);
672abd95342SNiranjan Hasabnis   }
673abd95342SNiranjan Hasabnis   // Currently I am not caching the results because we do not return
674abd95342SNiranjan Hasabnis   // default values of these properties. Instead if the property is
675abd95342SNiranjan Hasabnis   // missing, we return std::nullopt so that the users can resort to
676abd95342SNiranjan Hasabnis   // the default value however they want.
677abd95342SNiranjan Hasabnis   if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
678bdeee9b1SNiranjan Hasabnis     return iface.getDevicePropertyValue(entry);
679abd95342SNiranjan Hasabnis   else
680bdeee9b1SNiranjan Hasabnis     return detail::getDevicePropertyValue(entry);
681abd95342SNiranjan Hasabnis }
682abd95342SNiranjan Hasabnis 
6833ba14fa0SAlex Zinenko //===----------------------------------------------------------------------===//
6843ba14fa0SAlex Zinenko // DataLayoutSpecInterface
6853ba14fa0SAlex Zinenko //===----------------------------------------------------------------------===//
6863ba14fa0SAlex Zinenko 
6873ba14fa0SAlex Zinenko void DataLayoutSpecInterface::bucketEntriesByType(
6883ba14fa0SAlex Zinenko     DenseMap<TypeID, DataLayoutEntryList> &types,
689195730a6SRiver Riddle     DenseMap<StringAttr, DataLayoutEntryInterface> &ids) {
6903ba14fa0SAlex Zinenko   for (DataLayoutEntryInterface entry : getEntries()) {
69168f58812STres Popp     if (auto type = llvm::dyn_cast_if_present<Type>(entry.getKey()))
6923ba14fa0SAlex Zinenko       types[type.getTypeID()].push_back(entry);
6933ba14fa0SAlex Zinenko     else
694*9192367aSKazu Hirata       ids[llvm::cast<StringAttr>(entry.getKey())] = entry;
6953ba14fa0SAlex Zinenko   }
6963ba14fa0SAlex Zinenko }
6973ba14fa0SAlex Zinenko 
6983ba14fa0SAlex Zinenko LogicalResult mlir::detail::verifyDataLayoutSpec(DataLayoutSpecInterface spec,
6993ba14fa0SAlex Zinenko                                                  Location loc) {
7003ba14fa0SAlex Zinenko   // First, verify individual entries.
7013ba14fa0SAlex Zinenko   for (DataLayoutEntryInterface entry : spec.getEntries())
7023ba14fa0SAlex Zinenko     if (failed(entry.verifyEntry(loc)))
7033ba14fa0SAlex Zinenko       return failure();
7043ba14fa0SAlex Zinenko 
7053ba14fa0SAlex Zinenko   // Second, dispatch verifications of entry groups to types or dialects they
7067557530fSFangrui Song   // are associated with.
7073ba14fa0SAlex Zinenko   DenseMap<TypeID, DataLayoutEntryList> types;
708195730a6SRiver Riddle   DenseMap<StringAttr, DataLayoutEntryInterface> ids;
7093ba14fa0SAlex Zinenko   spec.bucketEntriesByType(types, ids);
7103ba14fa0SAlex Zinenko 
7113ba14fa0SAlex Zinenko   for (const auto &kvp : types) {
712*9192367aSKazu Hirata     auto sampleType = cast<Type>(kvp.second.front().getKey());
7135550c821STres Popp     if (isa<IndexType>(sampleType)) {
714b3386a73SAlex Zinenko       assert(kvp.second.size() == 1 &&
715b3386a73SAlex Zinenko              "expected one data layout entry for non-parametric 'index' type");
7165550c821STres Popp       if (!isa<IntegerAttr>(kvp.second.front().getValue()))
717b3386a73SAlex Zinenko         return emitError(loc)
718b3386a73SAlex Zinenko                << "expected integer attribute in the data layout entry for "
719b3386a73SAlex Zinenko                << sampleType;
720b3386a73SAlex Zinenko       continue;
721b3386a73SAlex Zinenko     }
722b3386a73SAlex Zinenko 
7235550c821STres Popp     if (isa<IntegerType, FloatType>(sampleType)) {
724f64170aaSAlex Zinenko       for (DataLayoutEntryInterface entry : kvp.second) {
7255550c821STres Popp         auto value = dyn_cast<DenseIntElementsAttr>(entry.getValue());
7268134a8fcSOleksandr "Alex" Zinenko         if (!value || !value.getElementType().isSignlessInteger(64)) {
7278134a8fcSOleksandr "Alex" Zinenko           emitError(loc) << "expected a dense i64 elements attribute in the "
728f64170aaSAlex Zinenko                             "data layout entry "
729f64170aaSAlex Zinenko                          << entry;
730f64170aaSAlex Zinenko           return failure();
731f64170aaSAlex Zinenko         }
732f64170aaSAlex Zinenko 
7338134a8fcSOleksandr "Alex" Zinenko         auto elements = llvm::to_vector<2>(value.getValues<uint64_t>());
734f64170aaSAlex Zinenko         unsigned numElements = elements.size();
735f64170aaSAlex Zinenko         if (numElements < 1 || numElements > 2) {
736f64170aaSAlex Zinenko           emitError(loc) << "expected 1 or 2 elements in the data layout entry "
737f64170aaSAlex Zinenko                          << entry;
738f64170aaSAlex Zinenko           return failure();
739f64170aaSAlex Zinenko         }
740f64170aaSAlex Zinenko 
7418134a8fcSOleksandr "Alex" Zinenko         uint64_t abi = elements[0];
7428134a8fcSOleksandr "Alex" Zinenko         uint64_t preferred = numElements == 2 ? elements[1] : abi;
743f64170aaSAlex Zinenko         if (preferred < abi) {
744f64170aaSAlex Zinenko           emitError(loc)
745f64170aaSAlex Zinenko               << "preferred alignment is expected to be greater than or equal "
746f64170aaSAlex Zinenko                  "to the abi alignment in data layout entry "
747f64170aaSAlex Zinenko               << entry;
748f64170aaSAlex Zinenko           return failure();
749f64170aaSAlex Zinenko         }
750f64170aaSAlex Zinenko       }
751f64170aaSAlex Zinenko       continue;
752f64170aaSAlex Zinenko     }
753f64170aaSAlex Zinenko 
7543ba14fa0SAlex Zinenko     if (isa<BuiltinDialect>(&sampleType.getDialect()))
7553ba14fa0SAlex Zinenko       return emitError(loc) << "unexpected data layout for a built-in type";
7563ba14fa0SAlex Zinenko 
7575550c821STres Popp     auto dlType = dyn_cast<DataLayoutTypeInterface>(sampleType);
7583ba14fa0SAlex Zinenko     if (!dlType)
7593ba14fa0SAlex Zinenko       return emitError(loc)
7603ba14fa0SAlex Zinenko              << "data layout specified for a type that does not support it";
7613ba14fa0SAlex Zinenko     if (failed(dlType.verifyEntries(kvp.second, loc)))
7623ba14fa0SAlex Zinenko       return failure();
7633ba14fa0SAlex Zinenko   }
7643ba14fa0SAlex Zinenko 
7653ba14fa0SAlex Zinenko   for (const auto &kvp : ids) {
766*9192367aSKazu Hirata     StringAttr identifier = cast<StringAttr>(kvp.second.getKey());
767120591e1SRiver Riddle     Dialect *dialect = identifier.getReferencedDialect();
7683ba14fa0SAlex Zinenko 
7693ba14fa0SAlex Zinenko     // Ignore attributes that belong to an unknown dialect, the dialect may
7703ba14fa0SAlex Zinenko     // actually implement the relevant interface but we don't know about that.
7713ba14fa0SAlex Zinenko     if (!dialect)
7723ba14fa0SAlex Zinenko       continue;
7733ba14fa0SAlex Zinenko 
77458e7bf78SRiver Riddle     const auto *iface = dyn_cast<DataLayoutDialectInterface>(dialect);
775f6faa71eSAlex Zinenko     if (!iface) {
776f6faa71eSAlex Zinenko       return emitError(loc)
777f6faa71eSAlex Zinenko              << "the '" << dialect->getNamespace()
778f6faa71eSAlex Zinenko              << "' dialect does not support identifier data layout entries";
779f6faa71eSAlex Zinenko     }
7803ba14fa0SAlex Zinenko     if (failed(iface->verifyEntry(kvp.second, loc)))
7813ba14fa0SAlex Zinenko       return failure();
7823ba14fa0SAlex Zinenko   }
7833ba14fa0SAlex Zinenko 
7843ba14fa0SAlex Zinenko   return success();
7853ba14fa0SAlex Zinenko }
7863ba14fa0SAlex Zinenko 
787abd95342SNiranjan Hasabnis LogicalResult
788abd95342SNiranjan Hasabnis mlir::detail::verifyTargetSystemSpec(TargetSystemSpecInterface spec,
789abd95342SNiranjan Hasabnis                                      Location loc) {
790abd95342SNiranjan Hasabnis   DenseMap<StringAttr, DataLayoutEntryInterface> deviceDescKeys;
791abd95342SNiranjan Hasabnis   DenseSet<TargetSystemSpecInterface::DeviceID> deviceIDs;
792abd95342SNiranjan Hasabnis   for (const auto &entry : spec.getEntries()) {
7935c1752e3SRolf Morel     auto targetDeviceSpec =
7945c1752e3SRolf Morel         dyn_cast<TargetDeviceSpecInterface>(entry.getValue());
7955c1752e3SRolf Morel 
7965c1752e3SRolf Morel     if (!targetDeviceSpec)
7975c1752e3SRolf Morel       return failure();
7985c1752e3SRolf Morel 
799abd95342SNiranjan Hasabnis     // First, verify individual target device desc specs.
800abd95342SNiranjan Hasabnis     if (failed(targetDeviceSpec.verifyEntry(loc)))
801abd95342SNiranjan Hasabnis       return failure();
802abd95342SNiranjan Hasabnis 
803abd95342SNiranjan Hasabnis     // Check that device IDs are unique across all entries.
8045c1752e3SRolf Morel     auto deviceID =
8055c1752e3SRolf Morel         llvm::dyn_cast<TargetSystemSpecInterface::DeviceID>(entry.getKey());
8065c1752e3SRolf Morel     if (!deviceID)
8075c1752e3SRolf Morel       return failure();
8085c1752e3SRolf Morel 
809abd95342SNiranjan Hasabnis     if (!deviceIDs.insert(deviceID).second) {
810abd95342SNiranjan Hasabnis       return failure();
811abd95342SNiranjan Hasabnis     }
812abd95342SNiranjan Hasabnis 
813abd95342SNiranjan Hasabnis     // collect all the keys used by all the target device specs.
814abd95342SNiranjan Hasabnis     for (DataLayoutEntryInterface entry : targetDeviceSpec.getEntries()) {
815abd95342SNiranjan Hasabnis       if (auto type = llvm::dyn_cast_if_present<Type>(entry.getKey())) {
816abd95342SNiranjan Hasabnis         // targetDeviceSpec does not support Type as a key.
817abd95342SNiranjan Hasabnis         return failure();
818abd95342SNiranjan Hasabnis       } else {
819*9192367aSKazu Hirata         deviceDescKeys[cast<StringAttr>(entry.getKey())] = entry;
820abd95342SNiranjan Hasabnis       }
821abd95342SNiranjan Hasabnis     }
822abd95342SNiranjan Hasabnis   }
823abd95342SNiranjan Hasabnis 
824abd95342SNiranjan Hasabnis   for (const auto &[keyName, keyVal] : deviceDescKeys) {
825abd95342SNiranjan Hasabnis     Dialect *dialect = keyName.getReferencedDialect();
826abd95342SNiranjan Hasabnis 
827abd95342SNiranjan Hasabnis     // Ignore attributes that belong to an unknown dialect, the dialect may
828abd95342SNiranjan Hasabnis     // actually implement the relevant interface but we don't know about that.
829abd95342SNiranjan Hasabnis     if (!dialect)
830abd95342SNiranjan Hasabnis       return failure();
831abd95342SNiranjan Hasabnis 
832abd95342SNiranjan Hasabnis     const auto *iface = dyn_cast<DataLayoutDialectInterface>(dialect);
833abd95342SNiranjan Hasabnis     if (!iface) {
834abd95342SNiranjan Hasabnis       return emitError(loc)
835abd95342SNiranjan Hasabnis              << "the '" << dialect->getNamespace()
836abd95342SNiranjan Hasabnis              << "' dialect does not support identifier data layout entries";
837abd95342SNiranjan Hasabnis     }
838abd95342SNiranjan Hasabnis     if (failed(iface->verifyEntry(keyVal, loc)))
839abd95342SNiranjan Hasabnis       return failure();
840abd95342SNiranjan Hasabnis   }
841abd95342SNiranjan Hasabnis 
842abd95342SNiranjan Hasabnis   return success();
843abd95342SNiranjan Hasabnis }
844abd95342SNiranjan Hasabnis 
8453ba14fa0SAlex Zinenko #include "mlir/Interfaces/DataLayoutAttrInterface.cpp.inc"
8463ba14fa0SAlex Zinenko #include "mlir/Interfaces/DataLayoutOpInterface.cpp.inc"
8473ba14fa0SAlex Zinenko #include "mlir/Interfaces/DataLayoutTypeInterface.cpp.inc"
848