1//===- DLTIAttrs.td - DLTI dialect attributes definition --*- 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#ifndef MLIR_DIALECT_DLTI_DLTIATTRS_TD 10#define MLIR_DIALECT_DLTI_DLTIATTRS_TD 11 12include "mlir/Dialect/DLTI/DLTI.td" 13include "mlir/Interfaces/DataLayoutInterfaces.td" 14include "mlir/IR/AttrTypeBase.td" 15 16class DLTIAttr<string name, list<Trait> traits = [], 17 string baseCppClass = "::mlir::Attribute"> 18 : AttrDef<DLTI_Dialect, name, traits, baseCppClass> { } 19 20//===----------------------------------------------------------------------===// 21// DataLayoutEntryAttr 22//===----------------------------------------------------------------------===// 23 24def DLTI_DataLayoutEntryAttr : 25 DLTIAttr<"DataLayoutEntry", [DataLayoutEntryInterface]> { 26 let summary = "An attribute to represent an entry of a data layout specification."; 27 let description = [{ 28 A data layout entry attribute is a key-value pair where the key is a type or 29 an identifier and the value is another attribute. These entries form a data 30 layout specification. 31 }]; 32 let parameters = (ins 33 "DataLayoutEntryKey":$key, "Attribute":$value 34 ); 35 // TODO: We do not generate storage class because llvm::PointerUnion 36 // does not work with hash_key method. 37 let genStorageClass = 0; 38 let mnemonic = "dl_entry"; 39 let genVerifyDecl = 0; 40 let hasCustomAssemblyFormat = 1; 41 let extraClassDeclaration = [{ 42 /// Returns the entry with the given key and value. 43 static DataLayoutEntryAttr get(StringAttr key, Attribute value); 44 static DataLayoutEntryAttr get(MLIRContext *context, Type key, Attribute value); 45 static DataLayoutEntryAttr get(Type key, Attribute value); 46 }]; 47} 48 49//===----------------------------------------------------------------------===// 50// DataLayoutSpecAttr 51//===----------------------------------------------------------------------===// 52 53def DLTI_DataLayoutSpecAttr : 54 DLTIAttr<"DataLayoutSpec", [DataLayoutSpecInterface]> { 55 let summary = "An attribute to represent a data layout specification."; 56 let description = [{ 57 A data layout specification is a list of entries that specify (partial) data 58 layout information. It is expected to be attached to operations that serve 59 as scopes for data layout requests. 60 }]; 61 let parameters = (ins 62 ArrayRefParameter<"DataLayoutEntryInterface", "">:$entries 63 ); 64 let mnemonic = "dl_spec"; 65 let genVerifyDecl = 1; 66 let hasCustomAssemblyFormat = 1; 67 let extraClassDeclaration = [{ 68 /// Combines this specification with `specs`, enclosing specifications listed 69 /// from outermost to innermost. This overwrites the older entries with the 70 /// same key as the newer entries if the entries are compatible. Returns null 71 /// if the specifications are not compatible. 72 DataLayoutSpecAttr combineWith(ArrayRef<DataLayoutSpecInterface> specs) const; 73 74 /// Returns the endiannes identifier. 75 StringAttr getEndiannessIdentifier(MLIRContext *context) const; 76 77 /// Returns the alloca memory space identifier. 78 StringAttr getAllocaMemorySpaceIdentifier(MLIRContext *context) const; 79 80 /// Returns the program memory space identifier. 81 StringAttr getProgramMemorySpaceIdentifier(MLIRContext *context) const; 82 83 /// Returns the global memory space identifier. 84 StringAttr getGlobalMemorySpaceIdentifier(MLIRContext *context) const; 85 86 /// Returns the stack alignment identifier. 87 StringAttr getStackAlignmentIdentifier(MLIRContext *context) const; 88 89 /// Returns the attribute associated with the key. 90 FailureOr<Attribute> query(DataLayoutEntryKey key) { 91 return ::llvm::cast<mlir::DataLayoutSpecInterface>(*this).queryHelper(key); 92 } 93 }]; 94} 95 96//===----------------------------------------------------------------------===// 97// MapAttr 98//===----------------------------------------------------------------------===// 99 100def DLTI_MapAttr : DLTIAttr<"Map", [DLTIQueryInterface]> { 101 let summary = "A mapping of DLTI-information by way of key-value pairs"; 102 let description = [{ 103 A Data Layout and Target Information map is a list of entries effectively 104 encoding a dictionary, mapping DLTI-related keys to DLTI-related values. 105 106 This attribute's main purpose is to facilate querying IR for arbitrary 107 key-value associations that encode DLTI. Facility functions exist to perform 108 recursive lookups on nested DLTI-map/query interface-implementing 109 attributes. 110 111 Consider the following flat encoding of a single-key dictionary 112 ``` 113 #dlti.map<"CPU::cache::L1::size_in_bytes" = 65536 : i32>> 114 ``` 115 versus nested maps, which make it possible to obtain sub-dictionaries of 116 related information (with the following example making use of other 117 attributes that also implement the `DLTIQueryInterface`): 118 ``` 119 #dlti.target_system_spec<"CPU" = 120 #dlti.target_device_spec<"cache" = 121 #dlti.map<"L1" = #dlti.map<"size_in_bytes" = 65536 : i32>, 122 "L1d" = #dlti.map<"size_in_bytes" = 32768 : i32> >>> 123 ``` 124 125 With the flat encoding, the implied structure of the key is ignored, that is 126 the only successful query (as expressed in the Transform Dialect) is: 127 `transform.dlti.query ["CPU::cache::L1::size_in_bytes"] at %op`, 128 where `%op` is a handle to an operation which associates the flat-encoding 129 `#dlti.map` attribute. 130 131 For querying nested dictionaries, the relevant keys need to be separately 132 provided. That is, if `%op` is an handle to an op which has the nesting 133 `#dlti.target_system_spec`-attribute from above attached, then 134 `transform.dlti.query ["CPU","cache","L1","size_in_bytes"] at %op` gives 135 back the first leaf value contained. To access the other leaf, we need to do 136 `transform.dlti.query ["CPU","cache","L1d","size_in_bytes"] at %op`. 137 }]; 138 let parameters = (ins 139 ArrayRefParameter<"DataLayoutEntryInterface", "">:$entries 140 ); 141 let mnemonic = "map"; 142 let genVerifyDecl = 1; 143 let hasCustomAssemblyFormat = 1; 144 let extraClassDeclaration = [{ 145 /// Returns the attribute associated with the key. 146 FailureOr<Attribute> query(DataLayoutEntryKey key) { 147 for (DataLayoutEntryInterface entry : getEntries()) 148 if (entry.getKey() == key) 149 return entry.getValue(); 150 return ::mlir::failure(); 151 } 152 }]; 153} 154 155//===----------------------------------------------------------------------===// 156// TargetSystemSpecAttr 157//===----------------------------------------------------------------------===// 158 159def DLTI_TargetSystemSpecAttr : 160 DLTIAttr<"TargetSystemSpec", [TargetSystemSpecInterface]> { 161 let summary = "An attribute to represent target system specification."; 162 let description = [{ 163 A system specification describes the overall system containing 164 multiple devices, with each device having a unique ID (string) 165 and its corresponding TargetDeviceSpec object. 166 167 Example: 168 ``` 169 dlti.target_system_spec = 170 #dlti.target_system_spec< 171 "CPU" = #dlti.target_device_spec< 172 "L1_cache_size_in_bytes" = 4096: ui32>, 173 "GPU" = #dlti.target_device_spec< 174 "max_vector_op_width" = 64 : ui32>, 175 "XPU" = #dlti.target_device_spec< 176 "max_vector_op_width" = 4096 : ui32>> 177 ``` 178 179 The verifier checks that keys are strings and pointed to values implement 180 DLTI's TargetDeviceSpecInterface. 181 }]; 182 let parameters = (ins 183 ArrayRefParameter<"DataLayoutEntryInterface">:$entries 184 ); 185 let mnemonic = "target_system_spec"; 186 let genVerifyDecl = 1; 187 let hasCustomAssemblyFormat = 1; 188 let extraClassDeclaration = [{ 189 /// Return the device specification that matches the given device ID 190 std::optional<TargetDeviceSpecInterface> 191 getDeviceSpecForDeviceID( 192 TargetSystemSpecInterface::DeviceID deviceID); 193 194 /// Returns the attribute associated with the key. 195 FailureOr<Attribute> query(DataLayoutEntryKey key) const { 196 return ::llvm::cast<mlir::TargetSystemSpecInterface>(*this).queryHelper(key); 197 } 198 }]; 199 let extraClassDefinition = [{ 200 std::optional<TargetDeviceSpecInterface> 201 $cppClass::getDeviceSpecForDeviceID( 202 TargetSystemSpecInterface::DeviceID deviceID) { 203 for (const auto& entry : getEntries()) { 204 if (entry.getKey() == DataLayoutEntryKey(deviceID)) 205 if (auto deviceSpec = 206 ::llvm::dyn_cast<TargetDeviceSpecInterface>(entry.getValue())) 207 return deviceSpec; 208 } 209 return std::nullopt; 210 } 211 }]; 212} 213 214//===----------------------------------------------------------------------===// 215// TargetDeviceSpecAttr 216//===----------------------------------------------------------------------===// 217 218def DLTI_TargetDeviceSpecAttr : 219 DLTIAttr<"TargetDeviceSpec", [TargetDeviceSpecInterface]> { 220 let summary = "An attribute to represent target device specification."; 221 let description = [{ 222 Each device specification describes a single device and its 223 hardware properties. Each device specification can contain any number 224 of optional hardware properties (e.g., max_vector_op_width below). 225 226 Example: 227 ``` 228 #dlti.target_device_spec<"max_vector_op_width" = 64 : ui32> 229 ``` 230 }]; 231 let parameters = (ins 232 ArrayRefParameter<"DataLayoutEntryInterface">:$entries 233 ); 234 let mnemonic = "target_device_spec"; 235 let genVerifyDecl = 1; 236 let hasCustomAssemblyFormat = 1; 237 238 let extraClassDeclaration = [{ 239 /// Returns the attribute associated with the key. 240 FailureOr<Attribute> query(DataLayoutEntryKey key) const { 241 return ::llvm::cast<mlir::TargetDeviceSpecInterface>(*this).queryHelper(key); 242 } 243 }]; 244} 245 246#endif // MLIR_DIALECT_DLTI_DLTIATTRS_TD 247