1//===- DataLayoutInterfaces.td - Data layout interfaces ----*- tablegen -*-===// 2// 3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4// See https://llvm.org/LICENSE.txt for license information. 5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6// 7//===----------------------------------------------------------------------===// 8// 9// Defines the interfaces for the data layout specification, operations to which 10// they can be attached, and types that are subject to data layout. 11// 12//===----------------------------------------------------------------------===// 13 14#ifndef MLIR_DATALAYOUTINTERFACES 15#define MLIR_DATALAYOUTINTERFACES 16 17include "mlir/IR/OpBase.td" 18 19//===----------------------------------------------------------------------===// 20// Attribute interfaces 21//===----------------------------------------------------------------------===// 22 23def DataLayoutEntryInterface : AttrInterface<"DataLayoutEntryInterface"> { 24 let cppNamespace = "::mlir"; 25 26 let description = [{ 27 Attribute interface describing an entry in a data layout specification. 28 29 A data layout specification entry is a key-value pair. Its key is either a 30 type, when the entry is related to a type or a class of types, or an 31 identifier, when it is not. `DataLayoutEntryKey` is an alias allowing one 32 to use both key types. Its value is an arbitrary attribute that is 33 interpreted either by the type for type keys or by the dialect containing 34 the identifier for identifier keys. The interface provides a hook that 35 can be used by specific implementations to delegate the verification of 36 attribute fitness for a particular key to the relevant type or dialect. 37 }]; 38 39 let methods = [ 40 InterfaceMethod< 41 /*description=*/"Returns the key of the this layout entry.", 42 /*retTy=*/"::mlir::DataLayoutEntryKey", 43 /*methodName=*/"getKey", 44 /*args=*/(ins) 45 >, 46 InterfaceMethod< 47 /*description=*/"Returns the value of this layout entry.", 48 /*retTy=*/"::mlir::Attribute", 49 /*methodName=*/"getValue", 50 /*args=*/(ins) 51 >, 52 InterfaceMethod< 53 /*description=*/"Checks that the entry is well-formed, reports errors " 54 "at the provided location.", 55 /*retTy=*/"::mlir::LogicalResult", 56 /*methodName=*/"verifyEntry", 57 /*args=*/(ins "::mlir::Location":$loc), 58 /*methodBody=*/"", 59 /*defaultImplementation=*/[{ return ::mlir::success(); }] 60 > 61 ]; 62 63 let extraClassDeclaration = [{ 64 /// Returns `true` if the key of this entry is a type. 65 bool isTypeEntry() { 66 return getKey().is<::mlir::Type>(); 67 } 68 }]; 69} 70 71def DataLayoutSpecInterface : AttrInterface<"DataLayoutSpecInterface"> { 72 let cppNamespace = "::mlir"; 73 74 let description = [{ 75 Attribute interface describing a data layout specification. 76 77 A data layout specification is seen as a sequence of entries, each of which 78 is an attribute implementing the data layout entry interface. It assumes 79 a contiguous underlying storage for entries. The interface provides a hook 80 for implementations to verify the well-formedness of the specification, 81 with a default implementation that verifies the absence of entries with 82 duplicate keys and the well-formedness of each individual entry before 83 dispatching to the type or dialect the entry is associated with. 84 85 Data layout specifications may need to be combined in case they appear on 86 nested operations subject to layout, or to ensure the validity of layout 87 modification. Concrete specification attributes must implement the 88 corresponding hook. 89 }]; 90 // The underlying storage being contiguous may be revised in the future, but 91 // care must be taken to avoid materializing or copying the entire list of 92 // entries. 93 94 let methods = [ 95 InterfaceMethod< 96 /*description=*/"Combines the current layout with the given list of " 97 "layouts, provided from the outermost (oldest) to the " 98 "innermost (newest). Returns null on failure.", 99 /*retTy=*/"::mlir::DataLayoutSpecInterface", 100 /*methodName=*/"combineWith", 101 /*args=*/(ins "::llvm::ArrayRef<::mlir::DataLayoutSpecInterface>":$specs) 102 >, 103 InterfaceMethod< 104 /*description=*/"Returns the list of layout entries.", 105 /*retTy=*/"::mlir::DataLayoutEntryListRef", 106 /*methodName=*/"getEntries", 107 /*args=*/(ins) 108 >, 109 // Implementations may override this if they have an efficient lookup 110 // mechanism. 111 InterfaceMethod< 112 /*description=*/"Returns a copy of the entries related to a specific " 113 "type class regardles of type parameters. ", 114 /*retTy=*/"::mlir::DataLayoutEntryList", 115 /*methodName=*/"getSpecForType", 116 /*args=*/(ins "::mlir::TypeID":$type), 117 /*methodBody=*/"", 118 /*defaultImplementation=*/[{ 119 return ::mlir::detail::filterEntriesForType($_attr.getEntries(), type); 120 }] 121 >, 122 // Implementations may override this if they have an efficient lookup 123 // mechanism. 124 InterfaceMethod< 125 /*description=*/"Returns the entry related to the given identifier, if " 126 "present.", 127 /*retTy=*/"::mlir::DataLayoutEntryInterface", 128 /*methodName=*/"getSpecForIdentifier", 129 /*args=*/(ins "::mlir::StringAttr":$identifier), 130 /*methodBody=*/"", 131 /*defaultImplementation=*/[{ 132 return ::mlir::detail::filterEntryForIdentifier($_attr.getEntries(), 133 identifier); 134 }] 135 >, 136 InterfaceMethod< 137 /*description=*/"Verifies the validity of the specification and reports " 138 "any errors at the given location.", 139 /*retTy=*/"::mlir::LogicalResult", 140 /*methodName=*/"verifySpec", 141 /*args=*/(ins "::mlir::Location":$loc), 142 /*methodBody=*/"", 143 /*defaultImplementation=*/[{ 144 return ::mlir::detail::verifyDataLayoutSpec($_attr, loc); 145 }] 146 >, 147 ]; 148 149 let extraClassDeclaration = [{ 150 /// Returns a copy of the entries related to the type specified as template 151 /// parameter. 152 template <typename Ty> 153 DataLayoutEntryList getSpecForType() { 154 return getSpecForType(TypeID::get<Ty>()); 155 } 156 157 /// Populates the given maps with lists of entries grouped by the type or 158 /// identifier they are associated with. Users are not expected to call this 159 /// method directly. 160 void bucketEntriesByType( 161 ::llvm::DenseMap<::mlir::TypeID, ::mlir::DataLayoutEntryList> &types, 162 ::llvm::DenseMap<::mlir::StringAttr, 163 ::mlir::DataLayoutEntryInterface> &ids); 164 }]; 165} 166 167//===----------------------------------------------------------------------===// 168// Operation interface 169//===----------------------------------------------------------------------===// 170 171def DataLayoutOpInterface : OpInterface<"DataLayoutOpInterface"> { 172 let cppNamespace = "::mlir"; 173 174 let description = [{ 175 Interface for operations that can have a data layout specification attached. 176 177 The `DataLayout` object, which can be used for data layout queries, can be 178 constructed for such operations. The absence of a data layout specification 179 must be handled without failing. 180 181 Concrete operations must implement the hook returning the data layout 182 specification. They may optionally override the methods used in data layout 183 queries, default implementations of which provide predefined answers for 184 built-in types and dispatch to the type interface for all other types. These 185 methods must be idempotent, that is return the same result on repeated 186 queries with the same parameters. They are declared static and therefore 187 have no access to the operation or its attributes. Instead, they receive a 188 list of data layout entries relevant to the request. The entries are known 189 to have passed the spec and entry verifier. 190 }]; 191 192 let methods = [ 193 InterfaceMethod< 194 /*description=*/"Returns the data layout specification for this op, or " 195 "null if it does not exist.", 196 /*retTy=*/"::mlir::DataLayoutSpecInterface", 197 /*methodName=*/"getDataLayoutSpec", 198 /*args=*/(ins) 199 >, 200 StaticInterfaceMethod< 201 /*description=*/"Returns the size of the given type computed using the " 202 "relevant entries. The data layout object can be used " 203 "for recursive queries.", 204 /*retTy=*/"unsigned", 205 /*methodName=*/"getTypeSize", 206 /*args=*/(ins "::mlir::Type":$type, 207 "const ::mlir::DataLayout &":$dataLayout, 208 "::mlir::DataLayoutEntryListRef":$params), 209 /*methodBody=*/"", 210 /*defaultImplementation=*/[{ 211 unsigned bits = ConcreteOp::getTypeSizeInBits(type, dataLayout, params); 212 return ::llvm::divideCeil(bits, 8); 213 }] 214 >, 215 StaticInterfaceMethod< 216 /*description=*/"Returns the size of the given type in bits computed " 217 "using the relevant entries. The data layout object can " 218 "be used for recursive queries.", 219 /*retTy=*/"unsigned", 220 /*methodName=*/"getTypeSizeInBits", 221 /*args=*/(ins "::mlir::Type":$type, 222 "const ::mlir::DataLayout &":$dataLayout, 223 "::mlir::DataLayoutEntryListRef":$params), 224 /*methodBody=*/"", 225 /*defaultImplementation=*/[{ 226 return ::mlir::detail::getDefaultTypeSizeInBits(type, dataLayout, 227 params); 228 }] 229 >, 230 StaticInterfaceMethod< 231 /*description=*/"Returns the alignment required by the ABI for the given " 232 "type computed using the relevant entries. The data " 233 "layout object can be used for recursive queries.", 234 /*retTy=*/"unsigned", 235 /*methodName=*/"getTypeABIAlignment", 236 /*args=*/(ins "::mlir::Type":$type, 237 "const ::mlir::DataLayout &":$dataLayout, 238 "::mlir::DataLayoutEntryListRef":$params), 239 /*methodBody=*/"", 240 /*defaultImplementation=*/[{ 241 return ::mlir::detail::getDefaultABIAlignment(type, dataLayout, params); 242 }] 243 >, 244 StaticInterfaceMethod< 245 /*description=*/"Returns the alignment preferred by the given type " 246 "computed using the relevant entries. The data layout" 247 "object can be used for recursive queries.", 248 /*retTy=*/"unsigned", 249 /*methodName=*/"getTypePreferredAlignment", 250 /*args=*/(ins "::mlir::Type":$type, 251 "const ::mlir::DataLayout &":$dataLayout, 252 "::mlir::DataLayoutEntryListRef":$params), 253 /*methodBody=*/"", 254 /*defaultImplementation=*/[{ 255 return ::mlir::detail::getDefaultPreferredAlignment(type, dataLayout, 256 params); 257 }] 258 >, 259 ]; 260 261 let verify = [{ return ::mlir::detail::verifyDataLayoutOp($_op); }]; 262} 263 264//===----------------------------------------------------------------------===// 265// Type interface 266//===----------------------------------------------------------------------===// 267 268def DataLayoutTypeInterface : TypeInterface<"DataLayoutTypeInterface"> { 269 let cppNamespace = "::mlir"; 270 271 let description = [{ 272 Interface for types subject to data layout. 273 274 Types willing to be supported by the data layout subsystem should implement 275 this interface by providing implementations of functions querying their 276 size, required and preferred alignment. Each of these functions accepts as 277 arguments a data layout object that can be used to perform recursive queries 278 in the same scope, and a list of data layout entries relevant to this type. 279 Specifically, the entries are those that have as key _any instance_ of the 280 same type class as the current type. For example, if IntegerType had 281 implemented this interface, it would have received the entries with keys i1, 282 i2, i8, etc. regardless of the bitwidth of this type. This mechanism allows 283 types to "interpolate" the results in a type-specific way instead of listing 284 all possible types in the specification. 285 286 The list of entries may be empty, in which case the type must provide a 287 reasonable default value. The entries in the list are known to have passed 288 the spec and the entry verifiers, as well as the type-specified verifier if 289 provided. 290 291 In case of nested layout specs or spec changes, the type can override a hook 292 indicating whether the outer (old) and the inner (new) spec are compatible. 293 }]; 294 295 let methods = [ 296 InterfaceMethod< 297 /*description=*/"Returns the size of this type in bytes.", 298 /*retTy=*/"unsigned", 299 /*methodName=*/"getTypeSize", 300 /*args=*/(ins "const ::mlir::DataLayout &":$dataLayout, 301 "::mlir::DataLayoutEntryListRef":$params), 302 /*methodBody=*/"", 303 /*defaultImplementation=*/[{ 304 unsigned bits = $_type.getTypeSizeInBits(dataLayout, params); 305 return ::llvm::divideCeil(bits, 8); 306 }] 307 >, 308 InterfaceMethod< 309 /*description=*/"Returns the size of this type in bits.", 310 /*retTy=*/"unsigned", 311 /*methodName=*/"getTypeSizeInBits", 312 /*args=*/(ins "const ::mlir::DataLayout &":$dataLayout, 313 "::mlir::DataLayoutEntryListRef":$params) 314 >, 315 InterfaceMethod< 316 /*description=*/"Returns the ABI-required alignment for this type, " 317 "in bytes", 318 /*retTy=*/"unsigned", 319 /*methodName=*/"getABIAlignment", 320 /*args=*/(ins "const ::mlir::DataLayout &":$dataLayout, 321 "::mlir::DataLayoutEntryListRef":$params) 322 >, 323 InterfaceMethod< 324 /*description=*/"Returns the preferred alignment for this type, " 325 "in bytes.", 326 /*retTy=*/"unsigned", 327 /*methodName=*/"getPreferredAlignment", 328 /*args=*/(ins "const ::mlir::DataLayout &":$dataLayout, 329 "::mlir::DataLayoutEntryListRef":$params) 330 >, 331 InterfaceMethod< 332 /*desc=*/"Returns true if the two lists of entries are compatible, that " 333 "is, that `newLayout` spec entries can be nested in an op with " 334 "`oldLayout` spec entries.", 335 /*retTy=*/"bool", 336 /*methodName=*/"areCompatible", 337 /*args=*/(ins "::mlir::DataLayoutEntryListRef":$oldLayout, 338 "::mlir::DataLayoutEntryListRef":$newLayout), 339 /*methodBody=*/"", 340 /*defaultImplementation=*/[{ return true; }] 341 >, 342 InterfaceMethod< 343 /*description=*/"Verifies that the given list of entries is valid for " 344 "this type.", 345 /*retTy=*/"::mlir::LogicalResult", 346 /*methodName=*/"verifyEntries", 347 /*args=*/(ins "::mlir::DataLayoutEntryListRef":$entries, 348 "::mlir::Location":$loc), 349 /*methodBody=*/"", 350 /*defaultImplementation=*/[{ return ::mlir::success(); }] 351 >, 352 ]; 353} 354 355#endif // MLIR_DATALAYOUTINTERFACES 356