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.
reportMissingDataLayout(Type type)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;
32e244a6feSSimon Pilgrim   llvm::report_fatal_error(Twine(os.str()));
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.
getIndexBitwidth(DataLayoutEntryListRef params)37b3386a73SAlex Zinenko static unsigned getIndexBitwidth(DataLayoutEntryListRef params) {
38b3386a73SAlex Zinenko   if (params.empty())
39b3386a73SAlex Zinenko     return 64;
40b3386a73SAlex Zinenko   auto attr = params.front().getValue().cast<IntegerAttr>();
41b3386a73SAlex Zinenko   return attr.getValue().getZExtValue();
42b3386a73SAlex Zinenko }
43b3386a73SAlex Zinenko 
443ba14fa0SAlex Zinenko unsigned
getDefaultTypeSize(Type type,const DataLayout & dataLayout,ArrayRef<DataLayoutEntryInterface> params)453ba14fa0SAlex Zinenko mlir::detail::getDefaultTypeSize(Type type, const DataLayout &dataLayout,
463ba14fa0SAlex Zinenko                                  ArrayRef<DataLayoutEntryInterface> params) {
47f9cdc61dSAlex Zinenko   unsigned bits = getDefaultTypeSizeInBits(type, dataLayout, params);
48f9cdc61dSAlex Zinenko   return llvm::divideCeil(bits, 8);
49f9cdc61dSAlex Zinenko }
50f9cdc61dSAlex Zinenko 
getDefaultTypeSizeInBits(Type type,const DataLayout & dataLayout,DataLayoutEntryListRef params)51f9cdc61dSAlex Zinenko unsigned mlir::detail::getDefaultTypeSizeInBits(Type type,
52f9cdc61dSAlex Zinenko                                                 const DataLayout &dataLayout,
53f9cdc61dSAlex Zinenko                                                 DataLayoutEntryListRef params) {
543ba14fa0SAlex Zinenko   if (type.isa<IntegerType, FloatType>())
55f9cdc61dSAlex Zinenko     return type.getIntOrFloatBitWidth();
563ba14fa0SAlex Zinenko 
5731686d13STres Popp   if (auto ctype = type.dyn_cast<ComplexType>()) {
5831686d13STres Popp     auto et = ctype.getElementType();
5931686d13STres Popp     auto innerAlignment =
6031686d13STres Popp         getDefaultPreferredAlignment(et, dataLayout, params) * 8;
6131686d13STres Popp     auto 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.
69b3386a73SAlex Zinenko   if (type.isa<IndexType>())
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.
783ba14fa0SAlex Zinenko   if (auto vecType = type.dyn_cast<VectorType>())
79f9cdc61dSAlex Zinenko     return vecType.getNumElements() / vecType.getShape().back() *
80f9cdc61dSAlex Zinenko            llvm::PowerOf2Ceil(vecType.getShape().back()) *
81f9cdc61dSAlex Zinenko            dataLayout.getTypeSize(vecType.getElementType()) * 8;
823ba14fa0SAlex Zinenko 
833ba14fa0SAlex Zinenko   if (auto typeInterface = type.dyn_cast<DataLayoutTypeInterface>())
84f9cdc61dSAlex Zinenko     return typeInterface.getTypeSizeInBits(dataLayout, params);
853ba14fa0SAlex Zinenko 
863ba14fa0SAlex Zinenko   reportMissingDataLayout(type);
873ba14fa0SAlex Zinenko }
883ba14fa0SAlex Zinenko 
89*f64170aaSAlex Zinenko static DataLayoutEntryInterface
findEntryForIntegerType(IntegerType intType,ArrayRef<DataLayoutEntryInterface> params)90*f64170aaSAlex Zinenko findEntryForIntegerType(IntegerType intType,
91*f64170aaSAlex Zinenko                         ArrayRef<DataLayoutEntryInterface> params) {
92*f64170aaSAlex Zinenko   assert(!params.empty() && "expected non-empty parameter list");
93*f64170aaSAlex Zinenko   std::map<unsigned, DataLayoutEntryInterface> sortedParams;
94*f64170aaSAlex Zinenko   for (DataLayoutEntryInterface entry : params) {
95*f64170aaSAlex Zinenko     sortedParams.insert(std::make_pair(
96*f64170aaSAlex Zinenko         entry.getKey().get<Type>().getIntOrFloatBitWidth(), entry));
97*f64170aaSAlex Zinenko   }
98*f64170aaSAlex Zinenko   auto iter = sortedParams.lower_bound(intType.getWidth());
99*f64170aaSAlex Zinenko   if (iter == sortedParams.end())
100*f64170aaSAlex Zinenko     iter = std::prev(iter);
101*f64170aaSAlex Zinenko 
102*f64170aaSAlex Zinenko   return iter->second;
103*f64170aaSAlex Zinenko }
104*f64170aaSAlex Zinenko 
extractABIAlignment(DataLayoutEntryInterface entry)105*f64170aaSAlex Zinenko static unsigned extractABIAlignment(DataLayoutEntryInterface entry) {
106*f64170aaSAlex Zinenko   auto values =
107*f64170aaSAlex Zinenko       entry.getValue().cast<DenseIntElementsAttr>().getValues<int32_t>();
108*f64170aaSAlex Zinenko   return *values.begin() / 8u;
109*f64170aaSAlex Zinenko }
110*f64170aaSAlex Zinenko 
111*f64170aaSAlex Zinenko static unsigned
getIntegerTypeABIAlignment(IntegerType intType,ArrayRef<DataLayoutEntryInterface> params)112*f64170aaSAlex Zinenko getIntegerTypeABIAlignment(IntegerType intType,
113*f64170aaSAlex Zinenko                            ArrayRef<DataLayoutEntryInterface> params) {
114*f64170aaSAlex Zinenko   if (params.empty()) {
115*f64170aaSAlex Zinenko     return intType.getWidth() < 64
116*f64170aaSAlex Zinenko                ? llvm::PowerOf2Ceil(llvm::divideCeil(intType.getWidth(), 8))
117*f64170aaSAlex Zinenko                : 4;
118*f64170aaSAlex Zinenko   }
119*f64170aaSAlex Zinenko 
120*f64170aaSAlex Zinenko   return extractABIAlignment(findEntryForIntegerType(intType, params));
121*f64170aaSAlex Zinenko }
122*f64170aaSAlex Zinenko 
123*f64170aaSAlex Zinenko static unsigned
getFloatTypeABIAlignment(FloatType fltType,const DataLayout & dataLayout,ArrayRef<DataLayoutEntryInterface> params)124*f64170aaSAlex Zinenko getFloatTypeABIAlignment(FloatType fltType, const DataLayout &dataLayout,
125*f64170aaSAlex Zinenko                          ArrayRef<DataLayoutEntryInterface> params) {
126*f64170aaSAlex Zinenko   assert(params.size() <= 1 && "at most one data layout entry is expected for "
127*f64170aaSAlex Zinenko                                "the singleton floating-point type");
128*f64170aaSAlex Zinenko   if (params.empty())
129*f64170aaSAlex Zinenko     return llvm::PowerOf2Ceil(dataLayout.getTypeSize(fltType));
130*f64170aaSAlex Zinenko   return extractABIAlignment(params[0]);
131*f64170aaSAlex Zinenko }
132*f64170aaSAlex Zinenko 
getDefaultABIAlignment(Type type,const DataLayout & dataLayout,ArrayRef<DataLayoutEntryInterface> params)1333ba14fa0SAlex Zinenko unsigned mlir::detail::getDefaultABIAlignment(
1343ba14fa0SAlex Zinenko     Type type, const DataLayout &dataLayout,
1353ba14fa0SAlex Zinenko     ArrayRef<DataLayoutEntryInterface> params) {
1363ba14fa0SAlex Zinenko   // Natural alignment is the closest power-of-two number above.
137*f64170aaSAlex Zinenko   if (type.isa<VectorType>())
1383ba14fa0SAlex Zinenko     return llvm::PowerOf2Ceil(dataLayout.getTypeSize(type));
1393ba14fa0SAlex Zinenko 
140*f64170aaSAlex Zinenko   if (auto fltType = type.dyn_cast<FloatType>())
141*f64170aaSAlex Zinenko     return getFloatTypeABIAlignment(fltType, dataLayout, params);
142*f64170aaSAlex Zinenko 
143b3386a73SAlex Zinenko   // Index is an integer of some bitwidth.
144b3386a73SAlex Zinenko   if (type.isa<IndexType>())
145b3386a73SAlex Zinenko     return dataLayout.getTypeABIAlignment(
146b3386a73SAlex Zinenko         IntegerType::get(type.getContext(), getIndexBitwidth(params)));
147b3386a73SAlex Zinenko 
148*f64170aaSAlex Zinenko   if (auto intType = type.dyn_cast<IntegerType>())
149*f64170aaSAlex Zinenko     return getIntegerTypeABIAlignment(intType, params);
1503ba14fa0SAlex Zinenko 
15131686d13STres Popp   if (auto ctype = type.dyn_cast<ComplexType>())
15231686d13STres Popp     return getDefaultABIAlignment(ctype.getElementType(), dataLayout, params);
15331686d13STres Popp 
1543ba14fa0SAlex Zinenko   if (auto typeInterface = type.dyn_cast<DataLayoutTypeInterface>())
1553ba14fa0SAlex Zinenko     return typeInterface.getABIAlignment(dataLayout, params);
1563ba14fa0SAlex Zinenko 
1573ba14fa0SAlex Zinenko   reportMissingDataLayout(type);
1583ba14fa0SAlex Zinenko }
1593ba14fa0SAlex Zinenko 
extractPreferredAlignment(DataLayoutEntryInterface entry)160*f64170aaSAlex Zinenko static unsigned extractPreferredAlignment(DataLayoutEntryInterface entry) {
161*f64170aaSAlex Zinenko   auto values =
162*f64170aaSAlex Zinenko       entry.getValue().cast<DenseIntElementsAttr>().getValues<int32_t>();
163*f64170aaSAlex Zinenko   return *std::next(values.begin(), values.size() - 1) / 8u;
164*f64170aaSAlex Zinenko }
165*f64170aaSAlex Zinenko 
166*f64170aaSAlex Zinenko static unsigned
getIntegerTypePreferredAlignment(IntegerType intType,const DataLayout & dataLayout,ArrayRef<DataLayoutEntryInterface> params)167*f64170aaSAlex Zinenko getIntegerTypePreferredAlignment(IntegerType intType,
168*f64170aaSAlex Zinenko                                  const DataLayout &dataLayout,
169*f64170aaSAlex Zinenko                                  ArrayRef<DataLayoutEntryInterface> params) {
170*f64170aaSAlex Zinenko   if (params.empty())
171*f64170aaSAlex Zinenko     return llvm::PowerOf2Ceil(dataLayout.getTypeSize(intType));
172*f64170aaSAlex Zinenko 
173*f64170aaSAlex Zinenko   return extractPreferredAlignment(findEntryForIntegerType(intType, params));
174*f64170aaSAlex Zinenko }
175*f64170aaSAlex Zinenko 
176*f64170aaSAlex Zinenko static unsigned
getFloatTypePreferredAlignment(FloatType fltType,const DataLayout & dataLayout,ArrayRef<DataLayoutEntryInterface> params)177*f64170aaSAlex Zinenko getFloatTypePreferredAlignment(FloatType fltType, const DataLayout &dataLayout,
178*f64170aaSAlex Zinenko                                ArrayRef<DataLayoutEntryInterface> params) {
179*f64170aaSAlex Zinenko   assert(params.size() <= 1 && "at most one data layout entry is expected for "
180*f64170aaSAlex Zinenko                                "the singleton floating-point type");
181*f64170aaSAlex Zinenko   if (params.empty())
182*f64170aaSAlex Zinenko     return dataLayout.getTypeABIAlignment(fltType);
183*f64170aaSAlex Zinenko   return extractPreferredAlignment(params[0]);
184*f64170aaSAlex Zinenko }
185*f64170aaSAlex Zinenko 
getDefaultPreferredAlignment(Type type,const DataLayout & dataLayout,ArrayRef<DataLayoutEntryInterface> params)1863ba14fa0SAlex Zinenko unsigned mlir::detail::getDefaultPreferredAlignment(
1873ba14fa0SAlex Zinenko     Type type, const DataLayout &dataLayout,
1883ba14fa0SAlex Zinenko     ArrayRef<DataLayoutEntryInterface> params) {
1893ba14fa0SAlex Zinenko   // Preferred alignment is same as natural for floats and vectors.
190*f64170aaSAlex Zinenko   if (type.isa<VectorType>())
1913ba14fa0SAlex Zinenko     return dataLayout.getTypeABIAlignment(type);
1923ba14fa0SAlex Zinenko 
193*f64170aaSAlex Zinenko   if (auto fltType = type.dyn_cast<FloatType>())
194*f64170aaSAlex Zinenko     return getFloatTypePreferredAlignment(fltType, dataLayout, params);
195*f64170aaSAlex Zinenko 
196*f64170aaSAlex Zinenko   // Preferred alignment is the closest power-of-two number above for integers
1973ba14fa0SAlex Zinenko   // (ABI alignment may be smaller).
198*f64170aaSAlex Zinenko   if (auto intType = type.dyn_cast<IntegerType>())
199*f64170aaSAlex Zinenko     return getIntegerTypePreferredAlignment(intType, dataLayout, params);
200*f64170aaSAlex Zinenko 
201*f64170aaSAlex Zinenko   if (type.isa<IndexType>()) {
202*f64170aaSAlex Zinenko     return dataLayout.getTypePreferredAlignment(
203*f64170aaSAlex Zinenko         IntegerType::get(type.getContext(), getIndexBitwidth(params)));
204*f64170aaSAlex Zinenko   }
2053ba14fa0SAlex Zinenko 
20631686d13STres Popp   if (auto ctype = type.dyn_cast<ComplexType>())
20731686d13STres Popp     return getDefaultPreferredAlignment(ctype.getElementType(), dataLayout,
20831686d13STres Popp                                         params);
20931686d13STres Popp 
2103ba14fa0SAlex Zinenko   if (auto typeInterface = type.dyn_cast<DataLayoutTypeInterface>())
2113ba14fa0SAlex Zinenko     return typeInterface.getPreferredAlignment(dataLayout, params);
2123ba14fa0SAlex Zinenko 
2133ba14fa0SAlex Zinenko   reportMissingDataLayout(type);
2143ba14fa0SAlex Zinenko }
2153ba14fa0SAlex Zinenko 
2163ba14fa0SAlex Zinenko DataLayoutEntryList
filterEntriesForType(DataLayoutEntryListRef entries,TypeID typeID)2173ba14fa0SAlex Zinenko mlir::detail::filterEntriesForType(DataLayoutEntryListRef entries,
2183ba14fa0SAlex Zinenko                                    TypeID typeID) {
2193ba14fa0SAlex Zinenko   return llvm::to_vector<4>(llvm::make_filter_range(
2203ba14fa0SAlex Zinenko       entries, [typeID](DataLayoutEntryInterface entry) {
2213ba14fa0SAlex Zinenko         auto type = entry.getKey().dyn_cast<Type>();
2223ba14fa0SAlex Zinenko         return type && type.getTypeID() == typeID;
2233ba14fa0SAlex Zinenko       }));
2243ba14fa0SAlex Zinenko }
2253ba14fa0SAlex Zinenko 
2263ba14fa0SAlex Zinenko DataLayoutEntryInterface
filterEntryForIdentifier(DataLayoutEntryListRef entries,StringAttr id)2273ba14fa0SAlex Zinenko mlir::detail::filterEntryForIdentifier(DataLayoutEntryListRef entries,
228195730a6SRiver Riddle                                        StringAttr id) {
2293ba14fa0SAlex Zinenko   const auto *it = llvm::find_if(entries, [id](DataLayoutEntryInterface entry) {
230195730a6SRiver Riddle     if (!entry.getKey().is<StringAttr>())
2313ba14fa0SAlex Zinenko       return false;
232195730a6SRiver Riddle     return entry.getKey().get<StringAttr>() == id;
2333ba14fa0SAlex Zinenko   });
2343ba14fa0SAlex Zinenko   return it == entries.end() ? DataLayoutEntryInterface() : *it;
2353ba14fa0SAlex Zinenko }
2363ba14fa0SAlex Zinenko 
getSpec(Operation * operation)2371916b0e0SAlex Zinenko static DataLayoutSpecInterface getSpec(Operation *operation) {
2381916b0e0SAlex Zinenko   return llvm::TypeSwitch<Operation *, DataLayoutSpecInterface>(operation)
2391916b0e0SAlex Zinenko       .Case<ModuleOp, DataLayoutOpInterface>(
2401916b0e0SAlex Zinenko           [&](auto op) { return op.getDataLayoutSpec(); })
2411916b0e0SAlex Zinenko       .Default([](Operation *) {
2421916b0e0SAlex Zinenko         llvm_unreachable("expected an op with data layout spec");
2431916b0e0SAlex Zinenko         return DataLayoutSpecInterface();
2441916b0e0SAlex Zinenko       });
2451916b0e0SAlex Zinenko }
2461916b0e0SAlex Zinenko 
2473ba14fa0SAlex Zinenko /// Populates `opsWithLayout` with the list of proper ancestors of `leaf` that
2481916b0e0SAlex Zinenko /// are either modules or implement the `DataLayoutOpInterface`.
2491916b0e0SAlex Zinenko static void
collectParentLayouts(Operation * leaf,SmallVectorImpl<DataLayoutSpecInterface> & specs,SmallVectorImpl<Location> * opLocations=nullptr)2501916b0e0SAlex Zinenko collectParentLayouts(Operation *leaf,
2511916b0e0SAlex Zinenko                      SmallVectorImpl<DataLayoutSpecInterface> &specs,
2521916b0e0SAlex Zinenko                      SmallVectorImpl<Location> *opLocations = nullptr) {
2533ba14fa0SAlex Zinenko   if (!leaf)
2543ba14fa0SAlex Zinenko     return;
2553ba14fa0SAlex Zinenko 
2561916b0e0SAlex Zinenko   for (Operation *parent = leaf->getParentOp(); parent != nullptr;
2571916b0e0SAlex Zinenko        parent = parent->getParentOp()) {
2581916b0e0SAlex Zinenko     llvm::TypeSwitch<Operation *>(parent)
2591916b0e0SAlex Zinenko         .Case<ModuleOp>([&](ModuleOp op) {
2601916b0e0SAlex Zinenko           // Skip top-level module op unless it has a layout. Top-level module
2611916b0e0SAlex Zinenko           // without layout is most likely the one implicitly added by the
2621916b0e0SAlex Zinenko           // parser and it doesn't have location. Top-level null specification
2631916b0e0SAlex Zinenko           // would have had the same effect as not having a specification at all
2641916b0e0SAlex Zinenko           // (using type defaults).
2651916b0e0SAlex Zinenko           if (!op->getParentOp() && !op.getDataLayoutSpec())
2661916b0e0SAlex Zinenko             return;
2671916b0e0SAlex Zinenko           specs.push_back(op.getDataLayoutSpec());
2681916b0e0SAlex Zinenko           if (opLocations)
2691916b0e0SAlex Zinenko             opLocations->push_back(op.getLoc());
2701916b0e0SAlex Zinenko         })
2711916b0e0SAlex Zinenko         .Case<DataLayoutOpInterface>([&](DataLayoutOpInterface op) {
2721916b0e0SAlex Zinenko           specs.push_back(op.getDataLayoutSpec());
2731916b0e0SAlex Zinenko           if (opLocations)
2741916b0e0SAlex Zinenko             opLocations->push_back(op.getLoc());
2751916b0e0SAlex Zinenko         });
2763ba14fa0SAlex Zinenko   }
2773ba14fa0SAlex Zinenko }
2783ba14fa0SAlex Zinenko 
2793ba14fa0SAlex Zinenko /// Returns a layout spec that is a combination of the layout specs attached
2803ba14fa0SAlex Zinenko /// to the given operation and all its ancestors.
getCombinedDataLayout(Operation * leaf)2811916b0e0SAlex Zinenko static DataLayoutSpecInterface getCombinedDataLayout(Operation *leaf) {
2823ba14fa0SAlex Zinenko   if (!leaf)
2833ba14fa0SAlex Zinenko     return {};
2843ba14fa0SAlex Zinenko 
2851916b0e0SAlex Zinenko   assert((isa<ModuleOp, DataLayoutOpInterface>(leaf)) &&
2861916b0e0SAlex Zinenko          "expected an op with data layout spec");
2871916b0e0SAlex Zinenko 
2883ba14fa0SAlex Zinenko   SmallVector<DataLayoutOpInterface> opsWithLayout;
2891916b0e0SAlex Zinenko   SmallVector<DataLayoutSpecInterface> specs;
2901916b0e0SAlex Zinenko   collectParentLayouts(leaf, specs);
2913ba14fa0SAlex Zinenko 
2923ba14fa0SAlex Zinenko   // Fast track if there are no ancestors.
2931916b0e0SAlex Zinenko   if (specs.empty())
2941916b0e0SAlex Zinenko     return getSpec(leaf);
2953ba14fa0SAlex Zinenko 
2963ba14fa0SAlex Zinenko   // Create the list of non-null specs (null/missing specs can be safely
2973ba14fa0SAlex Zinenko   // ignored) from the outermost to the innermost.
2981916b0e0SAlex Zinenko   auto nonNullSpecs = llvm::to_vector<2>(llvm::make_filter_range(
2991916b0e0SAlex Zinenko       llvm::reverse(specs),
3001916b0e0SAlex Zinenko       [](DataLayoutSpecInterface iface) { return iface != nullptr; }));
3013ba14fa0SAlex Zinenko 
3023ba14fa0SAlex Zinenko   // Combine the specs using the innermost as anchor.
3031916b0e0SAlex Zinenko   if (DataLayoutSpecInterface current = getSpec(leaf))
3041916b0e0SAlex Zinenko     return current.combineWith(nonNullSpecs);
3051916b0e0SAlex Zinenko   if (nonNullSpecs.empty())
3063ba14fa0SAlex Zinenko     return {};
3071916b0e0SAlex Zinenko   return nonNullSpecs.back().combineWith(
3081916b0e0SAlex Zinenko       llvm::makeArrayRef(nonNullSpecs).drop_back());
3093ba14fa0SAlex Zinenko }
3103ba14fa0SAlex Zinenko 
verifyDataLayoutOp(Operation * op)3111916b0e0SAlex Zinenko LogicalResult mlir::detail::verifyDataLayoutOp(Operation *op) {
3121916b0e0SAlex Zinenko   DataLayoutSpecInterface spec = getSpec(op);
3133ba14fa0SAlex Zinenko   // The layout specification may be missing and it's fine.
3143ba14fa0SAlex Zinenko   if (!spec)
3153ba14fa0SAlex Zinenko     return success();
3163ba14fa0SAlex Zinenko 
3171916b0e0SAlex Zinenko   if (failed(spec.verifySpec(op->getLoc())))
3183ba14fa0SAlex Zinenko     return failure();
3193ba14fa0SAlex Zinenko   if (!getCombinedDataLayout(op)) {
3203ba14fa0SAlex Zinenko     InFlightDiagnostic diag =
3211916b0e0SAlex Zinenko         op->emitError()
3221916b0e0SAlex Zinenko         << "data layout does not combine with layouts of enclosing ops";
3231916b0e0SAlex Zinenko     SmallVector<DataLayoutSpecInterface> specs;
3241916b0e0SAlex Zinenko     SmallVector<Location> opLocations;
3251916b0e0SAlex Zinenko     collectParentLayouts(op, specs, &opLocations);
3261916b0e0SAlex Zinenko     for (Location loc : opLocations)
3271916b0e0SAlex Zinenko       diag.attachNote(loc) << "enclosing op with data layout";
3283ba14fa0SAlex Zinenko     return diag;
3293ba14fa0SAlex Zinenko   }
3303ba14fa0SAlex Zinenko   return success();
3313ba14fa0SAlex Zinenko }
3323ba14fa0SAlex Zinenko 
3333ba14fa0SAlex Zinenko //===----------------------------------------------------------------------===//
3343ba14fa0SAlex Zinenko // DataLayout
3353ba14fa0SAlex Zinenko //===----------------------------------------------------------------------===//
3363ba14fa0SAlex Zinenko 
3371916b0e0SAlex Zinenko template <typename OpTy>
checkMissingLayout(DataLayoutSpecInterface originalLayout,OpTy op)3381916b0e0SAlex Zinenko void checkMissingLayout(DataLayoutSpecInterface originalLayout, OpTy op) {
3393ba14fa0SAlex Zinenko   if (!originalLayout) {
3403ba14fa0SAlex Zinenko     assert((!op || !op.getDataLayoutSpec()) &&
3413ba14fa0SAlex Zinenko            "could not compute layout information for an op (failed to "
3423ba14fa0SAlex Zinenko            "combine attributes?)");
3433ba14fa0SAlex Zinenko   }
3441916b0e0SAlex Zinenko }
3453ba14fa0SAlex Zinenko 
DataLayout()346b3386a73SAlex Zinenko mlir::DataLayout::DataLayout() : DataLayout(ModuleOp()) {}
347b3386a73SAlex Zinenko 
DataLayout(DataLayoutOpInterface op)3481916b0e0SAlex Zinenko mlir::DataLayout::DataLayout(DataLayoutOpInterface op)
3491916b0e0SAlex Zinenko     : originalLayout(getCombinedDataLayout(op)), scope(op) {
35097335ad1SMarkus Böck #if LLVM_ENABLE_ABI_BREAKING_CHECKS
3511916b0e0SAlex Zinenko   checkMissingLayout(originalLayout, op);
3521916b0e0SAlex Zinenko   collectParentLayouts(op, layoutStack);
3531916b0e0SAlex Zinenko #endif
3541916b0e0SAlex Zinenko }
3551916b0e0SAlex Zinenko 
DataLayout(ModuleOp op)3561916b0e0SAlex Zinenko mlir::DataLayout::DataLayout(ModuleOp op)
3571916b0e0SAlex Zinenko     : originalLayout(getCombinedDataLayout(op)), scope(op) {
35897335ad1SMarkus Böck #if LLVM_ENABLE_ABI_BREAKING_CHECKS
3591916b0e0SAlex Zinenko   checkMissingLayout(originalLayout, op);
3601916b0e0SAlex Zinenko   collectParentLayouts(op, layoutStack);
3613ba14fa0SAlex Zinenko #endif
3623ba14fa0SAlex Zinenko }
3633ba14fa0SAlex Zinenko 
closest(Operation * op)364b614ada0STobias Gysi mlir::DataLayout mlir::DataLayout::closest(Operation *op) {
365b614ada0STobias Gysi   // Search the closest parent either being a module operation or implementing
366b614ada0STobias Gysi   // the data layout interface.
367b614ada0STobias Gysi   while (op) {
368b614ada0STobias Gysi     if (auto module = dyn_cast<ModuleOp>(op))
369b614ada0STobias Gysi       return DataLayout(module);
370b614ada0STobias Gysi     if (auto iface = dyn_cast<DataLayoutOpInterface>(op))
371b614ada0STobias Gysi       return DataLayout(iface);
372b614ada0STobias Gysi     op = op->getParentOp();
373b614ada0STobias Gysi   }
374b614ada0STobias Gysi   return DataLayout();
375b614ada0STobias Gysi }
376b614ada0STobias Gysi 
checkValid() const3773ba14fa0SAlex Zinenko void mlir::DataLayout::checkValid() const {
37897335ad1SMarkus Böck #if LLVM_ENABLE_ABI_BREAKING_CHECKS
3791916b0e0SAlex Zinenko   SmallVector<DataLayoutSpecInterface> specs;
3801916b0e0SAlex Zinenko   collectParentLayouts(scope, specs);
3811916b0e0SAlex Zinenko   assert(specs.size() == layoutStack.size() &&
3823ba14fa0SAlex Zinenko          "data layout object used, but no longer valid due to the change in "
3833ba14fa0SAlex Zinenko          "number of nested layouts");
3841916b0e0SAlex Zinenko   for (auto pair : llvm::zip(specs, layoutStack)) {
3851916b0e0SAlex Zinenko     Attribute newLayout = std::get<0>(pair);
3863ba14fa0SAlex Zinenko     Attribute origLayout = std::get<1>(pair);
3873ba14fa0SAlex Zinenko     assert(newLayout == origLayout &&
3883ba14fa0SAlex Zinenko            "data layout object used, but no longer valid "
3893ba14fa0SAlex Zinenko            "due to the change in layout attributes");
3903ba14fa0SAlex Zinenko   }
3913ba14fa0SAlex Zinenko #endif
3923ba14fa0SAlex Zinenko   assert(((!scope && !this->originalLayout) ||
3933ba14fa0SAlex Zinenko           (scope && this->originalLayout == getCombinedDataLayout(scope))) &&
3943ba14fa0SAlex Zinenko          "data layout object used, but no longer valid due to the change in "
3953ba14fa0SAlex Zinenko          "layout spec");
3963ba14fa0SAlex Zinenko }
3973ba14fa0SAlex Zinenko 
3983ba14fa0SAlex Zinenko /// Looks up the value for the given type key in the given cache. If there is no
3993ba14fa0SAlex Zinenko /// such value in the cache, compute it using the given callback and put it in
4003ba14fa0SAlex Zinenko /// the cache before returning.
cachedLookup(Type t,DenseMap<Type,unsigned> & cache,function_ref<unsigned (Type)> compute)4013ba14fa0SAlex Zinenko static unsigned cachedLookup(Type t, DenseMap<Type, unsigned> &cache,
4023ba14fa0SAlex Zinenko                              function_ref<unsigned(Type)> compute) {
4033ba14fa0SAlex Zinenko   auto it = cache.find(t);
4043ba14fa0SAlex Zinenko   if (it != cache.end())
4053ba14fa0SAlex Zinenko     return it->second;
4063ba14fa0SAlex Zinenko 
4073ba14fa0SAlex Zinenko   auto result = cache.try_emplace(t, compute(t));
4083ba14fa0SAlex Zinenko   return result.first->second;
4093ba14fa0SAlex Zinenko }
4103ba14fa0SAlex Zinenko 
getTypeSize(Type t) const4113ba14fa0SAlex Zinenko unsigned mlir::DataLayout::getTypeSize(Type t) const {
4123ba14fa0SAlex Zinenko   checkValid();
4133ba14fa0SAlex Zinenko   return cachedLookup(t, sizes, [&](Type ty) {
414842d2435SAlex Zinenko     DataLayoutEntryList list;
415842d2435SAlex Zinenko     if (originalLayout)
416842d2435SAlex Zinenko       list = originalLayout.getSpecForType(ty.getTypeID());
417842d2435SAlex Zinenko     if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
4181916b0e0SAlex Zinenko       return iface.getTypeSize(ty, *this, list);
4191916b0e0SAlex Zinenko     return detail::getDefaultTypeSize(ty, *this, list);
4203ba14fa0SAlex Zinenko   });
4213ba14fa0SAlex Zinenko }
4223ba14fa0SAlex Zinenko 
getTypeSizeInBits(Type t) const423f9cdc61dSAlex Zinenko unsigned mlir::DataLayout::getTypeSizeInBits(Type t) const {
424f9cdc61dSAlex Zinenko   checkValid();
425f9cdc61dSAlex Zinenko   return cachedLookup(t, bitsizes, [&](Type ty) {
426842d2435SAlex Zinenko     DataLayoutEntryList list;
427842d2435SAlex Zinenko     if (originalLayout)
428842d2435SAlex Zinenko       list = originalLayout.getSpecForType(ty.getTypeID());
429842d2435SAlex Zinenko     if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
430f9cdc61dSAlex Zinenko       return iface.getTypeSizeInBits(ty, *this, list);
431f9cdc61dSAlex Zinenko     return detail::getDefaultTypeSizeInBits(ty, *this, list);
432f9cdc61dSAlex Zinenko   });
433f9cdc61dSAlex Zinenko }
434f9cdc61dSAlex Zinenko 
getTypeABIAlignment(Type t) const4353ba14fa0SAlex Zinenko unsigned mlir::DataLayout::getTypeABIAlignment(Type t) const {
4363ba14fa0SAlex Zinenko   checkValid();
4373ba14fa0SAlex Zinenko   return cachedLookup(t, abiAlignments, [&](Type ty) {
438842d2435SAlex Zinenko     DataLayoutEntryList list;
439842d2435SAlex Zinenko     if (originalLayout)
440842d2435SAlex Zinenko       list = originalLayout.getSpecForType(ty.getTypeID());
441842d2435SAlex Zinenko     if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
4421916b0e0SAlex Zinenko       return iface.getTypeABIAlignment(ty, *this, list);
4431916b0e0SAlex Zinenko     return detail::getDefaultABIAlignment(ty, *this, list);
4443ba14fa0SAlex Zinenko   });
4453ba14fa0SAlex Zinenko }
4463ba14fa0SAlex Zinenko 
getTypePreferredAlignment(Type t) const4473ba14fa0SAlex Zinenko unsigned mlir::DataLayout::getTypePreferredAlignment(Type t) const {
4483ba14fa0SAlex Zinenko   checkValid();
4493ba14fa0SAlex Zinenko   return cachedLookup(t, preferredAlignments, [&](Type ty) {
450842d2435SAlex Zinenko     DataLayoutEntryList list;
451842d2435SAlex Zinenko     if (originalLayout)
452842d2435SAlex Zinenko       list = originalLayout.getSpecForType(ty.getTypeID());
453842d2435SAlex Zinenko     if (auto iface = dyn_cast_or_null<DataLayoutOpInterface>(scope))
4541916b0e0SAlex Zinenko       return iface.getTypePreferredAlignment(ty, *this, list);
4551916b0e0SAlex Zinenko     return detail::getDefaultPreferredAlignment(ty, *this, list);
4563ba14fa0SAlex Zinenko   });
4573ba14fa0SAlex Zinenko }
4583ba14fa0SAlex Zinenko 
4593ba14fa0SAlex Zinenko //===----------------------------------------------------------------------===//
4603ba14fa0SAlex Zinenko // DataLayoutSpecInterface
4613ba14fa0SAlex Zinenko //===----------------------------------------------------------------------===//
4623ba14fa0SAlex Zinenko 
bucketEntriesByType(DenseMap<TypeID,DataLayoutEntryList> & types,DenseMap<StringAttr,DataLayoutEntryInterface> & ids)4633ba14fa0SAlex Zinenko void DataLayoutSpecInterface::bucketEntriesByType(
4643ba14fa0SAlex Zinenko     DenseMap<TypeID, DataLayoutEntryList> &types,
465195730a6SRiver Riddle     DenseMap<StringAttr, DataLayoutEntryInterface> &ids) {
4663ba14fa0SAlex Zinenko   for (DataLayoutEntryInterface entry : getEntries()) {
4673ba14fa0SAlex Zinenko     if (auto type = entry.getKey().dyn_cast<Type>())
4683ba14fa0SAlex Zinenko       types[type.getTypeID()].push_back(entry);
4693ba14fa0SAlex Zinenko     else
470195730a6SRiver Riddle       ids[entry.getKey().get<StringAttr>()] = entry;
4713ba14fa0SAlex Zinenko   }
4723ba14fa0SAlex Zinenko }
4733ba14fa0SAlex Zinenko 
verifyDataLayoutSpec(DataLayoutSpecInterface spec,Location loc)4743ba14fa0SAlex Zinenko LogicalResult mlir::detail::verifyDataLayoutSpec(DataLayoutSpecInterface spec,
4753ba14fa0SAlex Zinenko                                                  Location loc) {
4763ba14fa0SAlex Zinenko   // First, verify individual entries.
4773ba14fa0SAlex Zinenko   for (DataLayoutEntryInterface entry : spec.getEntries())
4783ba14fa0SAlex Zinenko     if (failed(entry.verifyEntry(loc)))
4793ba14fa0SAlex Zinenko       return failure();
4803ba14fa0SAlex Zinenko 
4813ba14fa0SAlex Zinenko   // Second, dispatch verifications of entry groups to types or dialects they
4823ba14fa0SAlex Zinenko   // are are associated with.
4833ba14fa0SAlex Zinenko   DenseMap<TypeID, DataLayoutEntryList> types;
484195730a6SRiver Riddle   DenseMap<StringAttr, DataLayoutEntryInterface> ids;
4853ba14fa0SAlex Zinenko   spec.bucketEntriesByType(types, ids);
4863ba14fa0SAlex Zinenko 
4873ba14fa0SAlex Zinenko   for (const auto &kvp : types) {
4883ba14fa0SAlex Zinenko     auto sampleType = kvp.second.front().getKey().get<Type>();
489b3386a73SAlex Zinenko     if (sampleType.isa<IndexType>()) {
490b3386a73SAlex Zinenko       assert(kvp.second.size() == 1 &&
491b3386a73SAlex Zinenko              "expected one data layout entry for non-parametric 'index' type");
492b3386a73SAlex Zinenko       if (!kvp.second.front().getValue().isa<IntegerAttr>())
493b3386a73SAlex Zinenko         return emitError(loc)
494b3386a73SAlex Zinenko                << "expected integer attribute in the data layout entry for "
495b3386a73SAlex Zinenko                << sampleType;
496b3386a73SAlex Zinenko       continue;
497b3386a73SAlex Zinenko     }
498b3386a73SAlex Zinenko 
499*f64170aaSAlex Zinenko     if (sampleType.isa<IntegerType, FloatType>()) {
500*f64170aaSAlex Zinenko       for (DataLayoutEntryInterface entry : kvp.second) {
501*f64170aaSAlex Zinenko         auto value = entry.getValue().dyn_cast<DenseIntElementsAttr>();
502*f64170aaSAlex Zinenko         if (!value || !value.getElementType().isSignlessInteger(32)) {
503*f64170aaSAlex Zinenko           emitError(loc) << "expected a dense i32 elements attribute in the "
504*f64170aaSAlex Zinenko                             "data layout entry "
505*f64170aaSAlex Zinenko                          << entry;
506*f64170aaSAlex Zinenko           return failure();
507*f64170aaSAlex Zinenko         }
508*f64170aaSAlex Zinenko 
509*f64170aaSAlex Zinenko         auto elements = llvm::to_vector<2>(value.getValues<int32_t>());
510*f64170aaSAlex Zinenko         unsigned numElements = elements.size();
511*f64170aaSAlex Zinenko         if (numElements < 1 || numElements > 2) {
512*f64170aaSAlex Zinenko           emitError(loc) << "expected 1 or 2 elements in the data layout entry "
513*f64170aaSAlex Zinenko                          << entry;
514*f64170aaSAlex Zinenko           return failure();
515*f64170aaSAlex Zinenko         }
516*f64170aaSAlex Zinenko 
517*f64170aaSAlex Zinenko         int32_t abi = elements[0];
518*f64170aaSAlex Zinenko         int32_t preferred = numElements == 2 ? elements[1] : abi;
519*f64170aaSAlex Zinenko         if (preferred < abi) {
520*f64170aaSAlex Zinenko           emitError(loc)
521*f64170aaSAlex Zinenko               << "preferred alignment is expected to be greater than or equal "
522*f64170aaSAlex Zinenko                  "to the abi alignment in data layout entry "
523*f64170aaSAlex Zinenko               << entry;
524*f64170aaSAlex Zinenko           return failure();
525*f64170aaSAlex Zinenko         }
526*f64170aaSAlex Zinenko       }
527*f64170aaSAlex Zinenko       continue;
528*f64170aaSAlex Zinenko     }
529*f64170aaSAlex Zinenko 
5303ba14fa0SAlex Zinenko     if (isa<BuiltinDialect>(&sampleType.getDialect()))
5313ba14fa0SAlex Zinenko       return emitError(loc) << "unexpected data layout for a built-in type";
5323ba14fa0SAlex Zinenko 
5333ba14fa0SAlex Zinenko     auto dlType = sampleType.dyn_cast<DataLayoutTypeInterface>();
5343ba14fa0SAlex Zinenko     if (!dlType)
5353ba14fa0SAlex Zinenko       return emitError(loc)
5363ba14fa0SAlex Zinenko              << "data layout specified for a type that does not support it";
5373ba14fa0SAlex Zinenko     if (failed(dlType.verifyEntries(kvp.second, loc)))
5383ba14fa0SAlex Zinenko       return failure();
5393ba14fa0SAlex Zinenko   }
5403ba14fa0SAlex Zinenko 
5413ba14fa0SAlex Zinenko   for (const auto &kvp : ids) {
542195730a6SRiver Riddle     StringAttr identifier = kvp.second.getKey().get<StringAttr>();
543120591e1SRiver Riddle     Dialect *dialect = identifier.getReferencedDialect();
5443ba14fa0SAlex Zinenko 
5453ba14fa0SAlex Zinenko     // Ignore attributes that belong to an unknown dialect, the dialect may
5463ba14fa0SAlex Zinenko     // actually implement the relevant interface but we don't know about that.
5473ba14fa0SAlex Zinenko     if (!dialect)
5483ba14fa0SAlex Zinenko       continue;
5493ba14fa0SAlex Zinenko 
55058e7bf78SRiver Riddle     const auto *iface = dyn_cast<DataLayoutDialectInterface>(dialect);
551f6faa71eSAlex Zinenko     if (!iface) {
552f6faa71eSAlex Zinenko       return emitError(loc)
553f6faa71eSAlex Zinenko              << "the '" << dialect->getNamespace()
554f6faa71eSAlex Zinenko              << "' dialect does not support identifier data layout entries";
555f6faa71eSAlex Zinenko     }
5563ba14fa0SAlex Zinenko     if (failed(iface->verifyEntry(kvp.second, loc)))
5573ba14fa0SAlex Zinenko       return failure();
5583ba14fa0SAlex Zinenko   }
5593ba14fa0SAlex Zinenko 
5603ba14fa0SAlex Zinenko   return success();
5613ba14fa0SAlex Zinenko }
5623ba14fa0SAlex Zinenko 
5633ba14fa0SAlex Zinenko #include "mlir/Interfaces/DataLayoutAttrInterface.cpp.inc"
5643ba14fa0SAlex Zinenko #include "mlir/Interfaces/DataLayoutOpInterface.cpp.inc"
5653ba14fa0SAlex Zinenko #include "mlir/Interfaces/DataLayoutTypeInterface.cpp.inc"
566