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