1//===-- MemorySlotInterfaces.td - MemorySlot 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#ifndef MLIR_INTERFACES_MEMORYSLOTINTERFACES 10#define MLIR_INTERFACES_MEMORYSLOTINTERFACES 11 12include "mlir/IR/OpBase.td" 13 14def PromotableAllocationOpInterface 15 : OpInterface<"PromotableAllocationOpInterface"> { 16 let description = [{ 17 Describes an operation allocating a memory slot that can be promoted into 18 SSA values. 19 }]; 20 let cppNamespace = "::mlir"; 21 22 let methods = [ 23 InterfaceMethod<[{ 24 Returns a list of memory slots for which promotion should be attempted. 25 This only considers the local semantics of the allocator, ignoring 26 whether the slot pointer is properly used or not. This allocator is the 27 "owner" of the returned slots, meaning no two allocators should return 28 the same slot. The content of the memory slot must only be reachable 29 using loads and stores to the provided slot pointer, no aliasing is 30 allowed. 31 32 Promotion of the slot will lead to the slot pointer no longer being 33 used, leaving the content of the memory slot unreachable. 34 35 No IR mutation is allowed in this method. 36 }], "::llvm::SmallVector<::mlir::MemorySlot>", "getPromotableSlots", 37 (ins) 38 >, 39 InterfaceMethod<[{ 40 Provides the default Value of this memory slot. The provided Value 41 will be used as the reaching definition of loads done before any store. 42 This Value must outlive the promotion and dominate all the uses of this 43 slot's pointer. The provided builder can be used to create the default 44 value on the fly. 45 46 The builder is located at the beginning of the block where the slot 47 pointer is defined. 48 }], "::mlir::Value", "getDefaultValue", 49 (ins 50 "const ::mlir::MemorySlot &":$slot, 51 "::mlir::OpBuilder &":$builder) 52 >, 53 InterfaceMethod<[{ 54 Hook triggered for every new block argument added to a block. 55 This will only be called for slots declared by this operation. 56 57 The builder is located at the beginning of the block on call. All IR 58 mutations must happen through the builder. 59 }], 60 "void", "handleBlockArgument", 61 (ins 62 "const ::mlir::MemorySlot &":$slot, 63 "::mlir::BlockArgument":$argument, 64 "::mlir::OpBuilder &":$builder 65 ) 66 >, 67 InterfaceMethod<[{ 68 Hook triggered once the promotion of a slot is complete. This can 69 also clean up the created default value if necessary. 70 This will only be called for slots declared by this operation. 71 72 Must return a new promotable allocation op if this operation produced 73 multiple promotable slots, nullopt otherwise. 74 }], 75 "::std::optional<::mlir::PromotableAllocationOpInterface>", 76 "handlePromotionComplete", 77 (ins 78 "const ::mlir::MemorySlot &":$slot, 79 "::mlir::Value":$defaultValue, 80 "::mlir::OpBuilder &":$builder) 81 >, 82 ]; 83} 84 85def PromotableMemOpInterface : OpInterface<"PromotableMemOpInterface"> { 86 let description = [{ 87 Describes an operation that can load from memory slots and/or store 88 to memory slots. 89 90 For a memory operation on a slot to be valid, it must strictly operate 91 within the bounds of the slot. 92 93 If the same operation does both loads and stores on the same slot, the 94 load must semantically happen first. 95 }]; 96 let cppNamespace = "::mlir"; 97 98 let methods = [ 99 InterfaceMethod<[{ 100 Gets whether this operation loads from the specified slot. 101 102 No IR mutation is allowed in this method. 103 }], 104 "bool", "loadsFrom", 105 (ins "const ::mlir::MemorySlot &":$slot) 106 >, 107 InterfaceMethod<[{ 108 Gets whether this operation stores to the specified slot. 109 110 No IR mutation is allowed in this method. 111 }], 112 "bool", "storesTo", 113 (ins "const ::mlir::MemorySlot &":$slot) 114 >, 115 InterfaceMethod<[{ 116 Gets the value stored to the provided memory slot, or returns a null 117 value if this operation does not store to this slot. An operation 118 storing a value to a slot must always be able to provide the value it 119 stores. This method is only called once per slot promotion, and only 120 on operations that store to the slot according to the `storesTo` method. 121 The returned value must dominate all operations dominated by the storing 122 operation. 123 124 The builder is located immediately after the memory operation on call. 125 No IR deletion is allowed in this method. IR mutations must not 126 introduce new uses of the memory slot. Existing control flow must not 127 be modified. 128 }], 129 "::mlir::Value", "getStored", 130 (ins "const ::mlir::MemorySlot &":$slot, 131 "::mlir::OpBuilder &":$builder, 132 "::mlir::Value":$reachingDef, 133 "const ::mlir::DataLayout &":$dataLayout) 134 >, 135 InterfaceMethod<[{ 136 Checks that this operation can be promoted to no longer use the provided 137 blocking uses, in the context of promoting `slot`. 138 139 If the removal procedure of the use will require that other uses get 140 removed, that dependency should be added to the `newBlockingUses` 141 argument. Dependent uses must only be uses of results of this operation. 142 143 No IR mutation is allowed in this method. 144 }], "bool", "canUsesBeRemoved", 145 (ins "const ::mlir::MemorySlot &":$slot, 146 "const ::llvm::SmallPtrSetImpl<::mlir::OpOperand *> &":$blockingUses, 147 "::llvm::SmallVectorImpl<::mlir::OpOperand *> &":$newBlockingUses, 148 "const ::mlir::DataLayout &":$datalayout) 149 >, 150 InterfaceMethod<[{ 151 Transforms IR to ensure that the current operation does not use the 152 provided memory slot anymore. `reachingDefinition` contains the value 153 currently stored in the provided memory slot, immediately before the 154 current operation. 155 156 During the transformation, *no operation should be deleted*. 157 The operation can only schedule its own deletion by returning the 158 appropriate `DeletionKind`. The deletion must be legal assuming the 159 blocking uses passed through the `newBlockingUses` list in 160 `canUseBeRemoved` have been removed. 161 162 After calling this method, the blocking uses should have disappeared 163 or this operation should have scheduled its own deletion. 164 165 This method will only be called after ensuring promotion is allowed via 166 `canUseBeRemoved`. The requested blocking use removal may or may not 167 have been done at the point of calling this method, but it will be done 168 eventually. 169 170 The builder is located after the promotable operation on call. 171 }], 172 "::mlir::DeletionKind", 173 "removeBlockingUses", 174 (ins "const ::mlir::MemorySlot &":$slot, 175 "const ::llvm::SmallPtrSetImpl<mlir::OpOperand *> &":$blockingUses, 176 "::mlir::OpBuilder &":$builder, 177 "::mlir::Value":$reachingDefinition, 178 "const ::mlir::DataLayout &":$dataLayout) 179 >, 180 ]; 181} 182 183def PromotableOpInterface : OpInterface<"PromotableOpInterface"> { 184 let description = [{ 185 Describes an operation that can be transformed or deleted so it no longer 186 uses a provided value (blocking use), in case this would allow the promotion 187 of a memory slot. 188 }]; 189 let cppNamespace = "::mlir"; 190 191 let methods = [ 192 InterfaceMethod<[{ 193 Checks that this operation can be promoted to no longer use the provided 194 blocking uses, in order to allow optimization. 195 196 If the removal procedure of the use will require that other uses get 197 removed, that dependency should be added to the `newBlockingUses` 198 argument. Dependent uses must only be uses of results of this operation. 199 200 No IR mutation is allowed in this method. 201 }], "bool", "canUsesBeRemoved", 202 (ins "const ::llvm::SmallPtrSetImpl<::mlir::OpOperand *> &":$blockingUses, 203 "::llvm::SmallVectorImpl<::mlir::OpOperand *> &":$newBlockingUses, 204 "const ::mlir::DataLayout &":$datalayout) 205 >, 206 InterfaceMethod<[{ 207 Transforms IR to ensure that the current operation does not use the 208 provided blocking uses anymore. In contrast to 209 `PromotableMemOpInterface`, operations implementing this interface 210 must not need access to the reaching definition of the content of the 211 slot. 212 213 During the transformation, *no operation should be deleted*. 214 The operation can only schedule its own deletion by returning the 215 appropriate `DeletionKind`. The deletion must be legal assuming the 216 blocking uses passed through the `newBlockingUses` list in 217 `canUseBeRemoved` have been removed. 218 219 After calling this method, the blocking uses should have disappeared 220 or this operation should have scheduled its own deletion. 221 222 This method will only be called after ensuring promotion is allowed via 223 `canUseBeRemoved`. The requested blocking use removal may or may not 224 have been done at the point of calling this method, but it will be done 225 eventually. 226 227 The builder is located after the promotable operation on call. 228 }], 229 "::mlir::DeletionKind", 230 "removeBlockingUses", 231 (ins "const ::llvm::SmallPtrSetImpl<mlir::OpOperand *> &":$blockingUses, 232 "::mlir::OpBuilder &":$builder) 233 >, 234 InterfaceMethod<[{ 235 This method allows the promoted operation to visit the SSA values used 236 in place of the memory slot once the promotion process of the memory 237 slot is complete. 238 239 If this method returns true, the `visitReplacedValues` method on this 240 operation will be called after the main mutation stage finishes 241 (i.e., after all ops have been processed with `removeBlockingUses`). 242 243 Operations should only the replaced values if the intended 244 transformation applies to all the replaced values. Furthermore, replaced 245 values must not be deleted. 246 }], "bool", "requiresReplacedValues", (ins), [{}], 247 [{ return false; }] 248 >, 249 InterfaceMethod<[{ 250 Transforms the IR using the SSA values that replaced the memory slot. 251 252 This method will only be called after all blocking uses have been 253 scheduled for removal and if `requiresReplacedValues` returned 254 true. 255 256 The builder is located after the promotable operation on call. During 257 the transformation, *no operation should be deleted*. 258 }], 259 "void", "visitReplacedValues", 260 (ins "::llvm::ArrayRef<std::pair<::mlir::Operation*, ::mlir::Value>>":$mutatedDefs, 261 "::mlir::OpBuilder &":$builder), [{}], [{ return; }] 262 >, 263 ]; 264} 265 266def DestructurableAllocationOpInterface 267 : OpInterface<"DestructurableAllocationOpInterface"> { 268 let description = [{ 269 Describes operations allocating memory slots of aggregates that can be 270 destructured into multiple smaller allocations. 271 }]; 272 let cppNamespace = "::mlir"; 273 274 let methods = [ 275 InterfaceMethod<[{ 276 Returns the list of slots for which destructuring should be attempted, 277 specifying in which way the slot should be destructured into subslots. 278 The subslots are indexed by attributes. This computes the type of the 279 pointer for each subslot to be generated. The type of the memory slot 280 must implement `DestructurableTypeInterface`. 281 282 No IR mutation is allowed in this method. 283 }], 284 "::llvm::SmallVector<::mlir::DestructurableMemorySlot>", 285 "getDestructurableSlots", 286 (ins) 287 >, 288 InterfaceMethod<[{ 289 Destructures this slot into multiple subslots. The newly generated slots 290 may belong to a different allocator. The original slot must still exist 291 at the end of this call. Only generates subslots for the indices found in 292 `usedIndices` since all other subslots are unused. 293 294 The builder is located at the beginning of the block where the slot 295 pointer is defined. 296 }], 297 "::llvm::DenseMap<::mlir::Attribute, ::mlir::MemorySlot>", 298 "destructure", 299 (ins "const ::mlir::DestructurableMemorySlot &":$slot, 300 "const ::llvm::SmallPtrSetImpl<::mlir::Attribute> &":$usedIndices, 301 "::mlir::OpBuilder &":$builder, 302 "::mlir::SmallVectorImpl<::mlir::DestructurableAllocationOpInterface> &": 303 $newAllocators) 304 >, 305 InterfaceMethod<[{ 306 Hook triggered once the destructuring of a slot is complete, meaning the 307 original slot is no longer being refered to and could be deleted. 308 This will only be called for slots declared by this operation. 309 310 Must return a new destructurable allocation op if this hook creates 311 a new destructurable op, nullopt otherwise. 312 }], 313 "::std::optional<::mlir::DestructurableAllocationOpInterface>", 314 "handleDestructuringComplete", 315 (ins "const ::mlir::DestructurableMemorySlot &":$slot, 316 "::mlir::OpBuilder &":$builder) 317 >, 318 ]; 319} 320 321def SafeMemorySlotAccessOpInterface 322 : OpInterface<"SafeMemorySlotAccessOpInterface"> { 323 let description = [{ 324 Describes operations using memory slots in a safe manner. 325 }]; 326 let cppNamespace = "::mlir"; 327 328 let methods = [ 329 InterfaceMethod<[{ 330 Returns whether all accesses in this operation to the provided slot are 331 done in a safe manner. To be safe, the access most only access the slot 332 inside the bounds that its type implies. 333 334 If the safety of the accesses depends on the safety of the accesses to 335 further memory slots, the result of this method will be conditioned to 336 the safety of the accesses to the slots added by this method to 337 `mustBeSafelyUsed`. 338 339 No IR mutation is allowed in this method. 340 }], 341 "::llvm::LogicalResult", 342 "ensureOnlySafeAccesses", 343 (ins "const ::mlir::MemorySlot &":$slot, 344 "::mlir::SmallVectorImpl<::mlir::MemorySlot> &":$mustBeSafelyUsed, 345 "const ::mlir::DataLayout &":$dataLayout) 346 > 347 ]; 348} 349 350def DestructurableAccessorOpInterface 351 : OpInterface<"DestructurableAccessorOpInterface"> { 352 let description = [{ 353 Describes operations that can access a sub-element of a destructurable slot. 354 }]; 355 let cppNamespace = "::mlir"; 356 357 let methods = [ 358 InterfaceMethod<[{ 359 For a given destructurable memory slot, returns whether this operation can 360 rewire its uses of the slot to use the slots generated after 361 destructuring. This may involve creating new operations. 362 363 This method must also register the indices it will access within the 364 `usedIndices` set. If the accessor generates new slots mapping to 365 subelements, they must be registered in `mustBeSafelyUsed` to ensure 366 they are used in a safe manner. 367 368 No IR mutation is allowed in this method. 369 }], 370 "bool", 371 "canRewire", 372 (ins "const ::mlir::DestructurableMemorySlot &":$slot, 373 "::llvm::SmallPtrSetImpl<::mlir::Attribute> &":$usedIndices, 374 "::mlir::SmallVectorImpl<::mlir::MemorySlot> &":$mustBeSafelyUsed, 375 "const ::mlir::DataLayout &":$dataLayout) 376 >, 377 InterfaceMethod<[{ 378 Rewires the use of a slot to the generated subslots, without deleting 379 any operation. Returns whether the accessor should be deleted. 380 381 Deletion of operations is not allowed, only the accessor can be 382 scheduled for deletion by returning the appropriate value. 383 }], 384 "::mlir::DeletionKind", 385 "rewire", 386 (ins "const ::mlir::DestructurableMemorySlot &":$slot, 387 "::llvm::DenseMap<::mlir::Attribute, ::mlir::MemorySlot> &":$subslots, 388 "::mlir::OpBuilder &":$builder, 389 "const ::mlir::DataLayout &":$dataLayout) 390 > 391 ]; 392} 393 394def DestructurableTypeInterface 395 : TypeInterface<"DestructurableTypeInterface"> { 396 let description = [{ 397 Describes a type that can be broken down into indexable sub-element types. 398 }]; 399 let cppNamespace = "::mlir"; 400 401 let methods = [ 402 InterfaceMethod<[{ 403 Destructures the type into subelements into a map of index attributes to 404 types of subelements. Returns nothing if the type cannot be destructured. 405 }], 406 "::std::optional<::llvm::DenseMap<::mlir::Attribute, ::mlir::Type>>", 407 "getSubelementIndexMap", 408 (ins) 409 >, 410 InterfaceMethod<[{ 411 Indicates which type is held at the provided index, returning a null 412 Type if no type could be computed. While this can return information 413 even when the type cannot be completely destructured, it must be coherent 414 with the types returned by `getSubelementIndexMap` when they exist. 415 }], 416 "::mlir::Type", 417 "getTypeAtIndex", 418 (ins "::mlir::Attribute":$index) 419 > 420 ]; 421} 422 423#endif // MLIR_INTERFACES_MEMORYSLOTINTERFACES 424