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