MLIR  17.0.0git
BufferizableOpInterface.h
Go to the documentation of this file.
1 //===- BufferizableOpInterface.h - Bufferizable Ops -------------*- C++ -*-===//
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_BUFFERIZATION_IR_BUFFERIZABLEOPINTERFACE_H_
10 #define MLIR_DIALECT_BUFFERIZATION_IR_BUFFERIZABLEOPINTERFACE_H_
11 
12 #include "mlir/IR/Operation.h"
13 #include "mlir/IR/PatternMatch.h"
14 #include "mlir/Support/LLVM.h"
15 #include "llvm/ADT/SetVector.h"
16 #include <optional>
17 
18 #include "mlir/Dialect/Bufferization/IR/BufferizationEnums.h.inc"
19 
20 namespace mlir {
21 class OpBuilder;
22 
23 namespace bufferization {
24 
25 class AnalysisState;
26 class BufferizableOpInterface;
27 
28 class OpFilter {
29 public:
30  /// An op filter entry. Filters can be used to specify which ops should be
31  /// processed by the bufferization.
32  struct Entry {
33  /// If the filter function evaluates to `true`, the filter matches.
34  using FilterFn = std::function<bool(Operation *)>;
35 
36  /// Filter type: A filter can either be a DENY filter or an ALLOW filter.
37  enum FilterType : int8_t { DENY = 0, ALLOW = 1 };
38 
41  };
42 
43  /// Return whether the op is allowed or not.
44  ///
45  /// If the filter does not have an ALLOW rule, ops are allowed by default,
46  /// unless they are explicitly marked as DENY. If the filter has at least one
47  /// ALLOW rule, ops are denied by default and only allowed if they match
48  /// an ALLOW rule and no DENY rule.
49  bool isOpAllowed(Operation *op) const;
50 
51  /// Allow the given dialects.
52  ///
53  /// This function adds one or multiple ALLOW entries.
54  template <typename... DialectTs>
55  void allowDialect() {
56  // The following expands a call to allowDialectImpl for each dialect
57  // in 'DialectTs'.
58  (allowDialectImpl<DialectTs>(), ...);
59  }
60 
61  /// Deny the given dialects.
62  ///
63  /// This function adds one or multiple DENY entries.
64  template <typename... DialectTs>
65  void denyDialect() {
66  (denyDialectImpl<DialectTs>(), ...);
67  }
68 
69  /// Allow the given dialect.
70  ///
71  /// This function adds an ALLOW entry.
72  void allowDialect(StringRef dialectNamespace) {
73  Entry::FilterFn filterFn = [=](Operation *op) {
74  return op->getDialect()->getNamespace() == dialectNamespace;
75  };
76  entries.push_back(Entry{filterFn, Entry::FilterType::ALLOW});
77  }
78 
79  /// Allow the given ops.
80  ///
81  /// This function adds one or multiple ALLOW entries.
82  template <typename... OpTys>
83  void allowOperation() {
84  (allowOperationImpl<OpTys>(), ...);
85  }
86 
87  /// Deny the given ops.
88  ///
89  /// This function adds one or multiple DENY entries.
90  template <typename... OpTys>
91  void denyOperation() {
92  (denyOperationImpl<OpTys>(), ...);
93  }
94 
95  /// Allow the given op.
96  ///
97  /// This function adds an ALLOW entry.
98  void allowOperation(StringRef opName) {
99  Entry::FilterFn filterFn = [=](Operation *op) {
100  return op->getName().getStringRef() == opName;
101  };
102  allowOperation(filterFn);
103  }
104 
105  /// Deny the given op.
106  ///
107  /// This function adds a DENY entry.
108  void denyOperation(StringRef opName) {
109  Entry::FilterFn filterFn = [=](Operation *op) {
110  return op->getName().getStringRef() == opName;
111  };
112  denyOperation(filterFn);
113  }
114 
115  /// Allow ops that are matched by `fn`.
116  ///
117  /// This function adds an ALLOW entry.
119  entries.push_back(Entry{fn, Entry::FilterType::ALLOW});
120  }
121 
122  /// Deny ops that are matched by `fn`.
123  ///
124  /// This function adds a DENY entry.
126  entries.push_back(Entry{fn, Entry::FilterType::DENY});
127  }
128 
129 private:
130  /// Return `true` if the filter has at least one ALLOW rule.
131  bool hasAllowRule() const {
132  for (const Entry &e : entries)
133  if (e.type == Entry::FilterType::ALLOW)
134  return true;
135  return false;
136  }
137 
138  /// Allow a dialect.
139  template <typename DialectT>
140  void allowDialectImpl() {
141  allowDialect(DialectT::getDialectNamespace());
142  }
143 
144  /// Deny a dialect.
145  template <typename DialectT>
146  void denyDialectImpl() {
147  denyDialect(DialectT::getDialectNamespace());
148  }
149 
150  /// Allow an op.
151  template <typename OpTy>
152  void allowOperationImpl() {
153  allowOperation(OpTy::getOperationName());
154  }
155 
156  /// Deny an op.
157  template <typename OpTy>
158  void denyOperationImpl() {
159  denyOperation(OpTy::getOperationName());
160  }
161 
162  /// A list of filter entries that determine whether an op should be allowed or
163  /// denied. If the filter has an ALLOW rule, only ops that are allowed and not
164  /// denied are allowed. If the filter does not have an ALLOW rule, only ops
165  /// that are not denied are allowed.
166  SmallVector<Entry> entries;
167 };
168 
169 /// Options for BufferizableOpInterface-based bufferization.
171  /// Allocator function: Generate a memref allocation with the given type,
172  /// dynamic extents and alignment.
173  using AllocationFn = std::function<FailureOr<Value>(
174  OpBuilder &, Location, MemRefType, ValueRange, unsigned int)>;
175  /// Deallocator function: Deallocate a buffer that was allocated with
176  /// AllocatorFn.
178  std::function<LogicalResult(OpBuilder &, Location, Value)>;
179  /// Memcpy function: Generate a memcpy between two buffers.
180  using MemCpyFn =
181  std::function<LogicalResult(OpBuilder &, Location, Value, Value)>;
182  /// Initializer function for analysis state.
183  using AnalysisStateInitFn = std::function<void(AnalysisState &)>;
184  /// Tensor -> MemRef type converter.
185  /// Parameters: Value, memory space, bufferization options
186  using UnknownTypeConverterFn = std::function<BaseMemRefType(
187  Value, Attribute memorySpace, const BufferizationOptions &)>;
188 
190 
191  /// Try to cast the given op to BufferizableOpInterface if the op is allow
192  /// listed.
193  BufferizableOpInterface dynCastBufferizableOp(Operation *op) const;
194 
195  /// Try to cast the given value to BufferizableOpInterface if the op is allow
196  /// listed.
197  BufferizableOpInterface dynCastBufferizableOp(Value value) const;
198 
199  /// A filter that specifies which ops should be bufferized and which ops
200  /// should be ignored.
202 
203  /// Return `true` if the given op should be bufferized.
204  bool isOpAllowed(Operation *op) const;
205 
206  /// Helper functions for allocation, deallocation, memory copying.
207  std::optional<AllocationFn> allocationFn;
208  std::optional<DeallocationFn> deallocationFn;
209  std::optional<MemCpyFn> memCpyFn;
210 
211  /// Create a memref allocation with the given type and dynamic extents.
212  FailureOr<Value> createAlloc(OpBuilder &b, Location loc, MemRefType type,
213  ValueRange dynShape) const;
214 
215  /// Creates a memref deallocation. The given memref buffer must have been
216  /// allocated using `createAlloc`.
218  Value allocatedBuffer) const;
219 
220  /// Creates a memcpy between two given buffers.
222  Value to) const;
223 
224  /// Specifies whether not bufferizable ops are allowed in the input. If so,
225  /// bufferization.to_memref and bufferization.to_tensor ops are inserted at
226  /// the boundaries.
227  bool allowUnknownOps = false;
228 
229  /// Specifies whether function boundaries (ops in the func dialect) should be
230  /// bufferized or not.
232 
233  /// The default memory space that should be used when it cannot be inferred
234  /// from the context. If case of std::nullopt, bufferization fails when the
235  /// memory space cannot be inferred at any point.
236  std::optional<Attribute> defaultMemorySpace = Attribute();
237 
238  /// Certain ops have aliasing OpOperand/OpResult invariants (e.g., scf.for).
239  /// If this flag is set to `false`, those invariants are no longer enforced
240  /// with buffer copies.
241  ///
242  /// Note: Deactivating this flag can lead to incorrect bufferization results
243  /// when used incorrectly. This flag is useful with
244  /// `AlwaysCopyAnalysisState` which bufferizes all writing tensor
245  /// OpOperands out-of-place.
247 
248  /// This flag controls buffer types on function signatures.
249  ///
250  /// * InferLayoutMap: All function parameter types have a fully dynamic layout
251  /// map, but function result types are inferred from the body of the
252  /// function.
253  /// * FullyDynamicLayoutMap: All function parameter types and result types
254  /// have a fully dynamic layout map. This option is most efficient because
255  /// any layout map can be casted to a fully dynamic one.
256  /// * IdentityLayoutMap: All function parameter types and result types have a
257  /// static identity layout (i.e., no layout map). This option may introduce
258  /// additional buffer allocs and copies because layout maps cannot be casted
259  /// away.
260  ///
261  /// If `bufferizeFunctionBoundaries` is not set, this flag has no effect.
262  ///
263  /// Note: Inferred layout maps may not be desireable when interacting with
264  /// external functions, because the generated function signatures will be less
265  /// predictable.
267  LayoutMapOption::InferLayoutMap;
268 
269  /// Type converter from tensors to memrefs. This type converter is used if no
270  /// memref type could be inferred during bufferization. By default, a type
271  /// converter that returns a memref type with a fully dynamic layout map is
272  /// used.
274 
275  /// Specifies whether dealloc ops should be generated along with alloc ops. If
276  /// not, new memory allocations will leak.
277  bool createDeallocs = true;
278 
279  /// Seed for the analysis fuzzer. If set to `0`, the fuzzer is deactivated.
280  /// Should be used only with `testAnalysisOnly = true`.
281  unsigned analysisFuzzerSeed = 0;
282 
283  /// If set to `true`, the analysis is skipped. A buffer is copied before every
284  /// write. This flag cannot be used together with `testAnalysisOnly = true`.
285  bool copyBeforeWrite = false;
286 
287  /// If set to `true`, does not modify the IR apart from adding attributes (for
288  /// checking the results of the analysis) and post analysis steps.
289  bool testAnalysisOnly = false;
290 
291  /// If set to `true`, the IR is annotated with details about RaW conflicts.
292  /// For debugging only. Should be used together with `testAnalysisOnly`.
293  bool printConflicts = false;
294 
295  /// Buffer alignment for new memory allocations.
296  unsigned int bufferAlignment = 64;
297 
298  /// Initializer functions for analysis state. These can be used to
299  /// initialize dialect-specific analysis state.
301 };
302 
303 /// Specify fine-grain relationship between buffers to enable more analysis.
304 enum class BufferRelation {
305  None,
306  // TODO: ResultContainsOperand,
307  // TODO: OperandContainsResult,
308  Equivalent
309 };
310 
311 /// Return `true` if the given value is a BlockArgument of a func::FuncOp.
312 bool isFunctionArgument(Value value);
313 
314 /// AnalysisState provides a variety of helper functions for dealing with
315 /// tensor values.
317 public:
318  /// Determine which OpOperand* will alias with `result` if the op is
319  /// bufferized in place. Return an empty vector if the op is not bufferizable.
321 
322  /// Determine which OpResult will alias with `opOperand` if the op is
323  /// bufferized in place. Return an empty vector if the op is not bufferizable.
325 
326  /// Return true if `opOperand` bufferizes to a memory read. Return `true` if
327  /// the op is not bufferizable.
328  bool bufferizesToMemoryRead(OpOperand &opOperand) const;
329 
330  /// Return true if `opOperand` bufferizes to a memory write. Return true` if
331  /// the op is not bufferizable.
332  bool bufferizesToMemoryWrite(OpOperand &opOperand) const;
333 
334  /// Return true if `opOperand` does neither read nor write but bufferizes to
335  /// an alias. Return false if the op is not bufferizable.
336  bool bufferizesToAliasOnly(OpOperand &opOperand) const;
337 
338  /// Return true if a copy can always be avoided when allocating a new tensor
339  /// for the given OpOperand.
340  bool canOmitTensorCopy(OpOperand &opOperand) const;
341 
342  /// Return true if the given value is read by an op that bufferizes to a
343  /// memory read. Also takes into account ops that create an alias but do not
344  /// read by themselves (e.g., ExtractSliceOp).
345  bool isValueRead(Value value) const;
346 
347  /// Starting from `value`, follow the use-def chain in reverse, always
348  /// selecting the aliasing OpOperands. Find and return Values for which
349  /// `condition` evaluates to true. OpOperands of such matching Values are not
350  /// traversed any further.
351  ///
352  /// When reaching the end of a chain (BlockArgument or Value without aliasing
353  /// OpOperands), also return the last Value of that chain.
354  ///
355  /// Example:
356  ///
357  /// 8
358  /// |
359  /// 6* 7* +-----+----+
360  /// | | | |
361  /// 2* 3 4* 5
362  /// | | | |
363  /// +----------+----------+----------+
364  /// |
365  /// 1
366  ///
367  /// In the above example, Values with a star satisfy the condition. When
368  /// starting the traversal from Value 1, the resulting SetVector is:
369  /// { 2, 7, 8, 5 }
370  ///
371  /// If `followEquivalentOnly` is set, only equivalent OpOperands are selected.
374  llvm::function_ref<bool(Value)> condition,
375  bool followEquivalentOnly = false) const;
376 
377  /// Find the Values of the last preceding write of a given Value.
378  ///
379  /// Note: Unknown ops are handled conservatively and assumed to be writes.
380  /// Furthermore, BlockArguments are also assumed to be writes. There is no
381  /// analysis across block boundaries.
382  ///
383  /// Note: When reaching an end of the reverse SSA use-def chain, that value
384  /// is returned regardless of whether it is a memory write or not.
386 
387  /// Return `true` if the given OpResult has been decided to bufferize inplace.
388  virtual bool isInPlace(OpOperand &opOperand) const;
389 
390  /// Return true if `v1` and `v2` bufferize to equivalent buffers.
391  virtual bool areEquivalentBufferizedValues(Value v1, Value v2) const;
392 
393  /// Return true if `v1` and `v2` may bufferize to aliasing buffers.
394  virtual bool areAliasingBufferizedValues(Value v1, Value v2) const;
395 
396  /// Return `true` if the given tensor has undefined contents.
397  virtual bool hasUndefinedContents(OpOperand *opOperand) const;
398 
399  /// Return true if the given tensor (or an aliasing tensor) is yielded from
400  /// the containing block. Also include all aliasing tensors in the same block.
401  ///
402  /// Note: In the absence of an analysis, an implementation may return true for
403  /// any given tensor.
404  virtual bool isTensorYielded(Value tensor) const;
405 
406  /// Return a reference to the BufferizationOptions.
407  const BufferizationOptions &getOptions() const { return options; }
408 
409  AnalysisState(const BufferizationOptions &options);
410 
411  // AnalysisState should be passed as a reference.
412  AnalysisState(const AnalysisState &) = delete;
413 
414  virtual ~AnalysisState() = default;
415 
416  static bool classof(const AnalysisState *base) { return true; }
417 
418  TypeID getType() const { return type; }
419 
420 protected:
421  AnalysisState(const BufferizationOptions &options, TypeID type);
422 
423 private:
424  /// A reference to current bufferization options.
425  const BufferizationOptions &options;
426 
427  /// The type of analysis.
428  TypeID type;
429 };
430 
431 /// Create an AllocTensorOp for the given shaped value (memref or tensor).
432 /// If `copy` is set, the shaped value is copied. Otherwise, a tensor with
433 /// undefined contents is allocated.
436  bool escape, const BufferizationOptions &options,
437  bool copy = true);
438 
439 /// Return `true` if the allocation of the given op is guaranteed to not escape
440 /// the containing block.
441 bool allocationDoesNotEscape(OpResult opResult);
442 
443 /// Lookup the buffer for the given value. If the value was not bufferized
444 /// yet, wrap it in a ToMemrefOp. Otherwise, it is the result of a ToTensorOp,
445 /// from which the memref operand is returned.
447  const BufferizationOptions &options);
448 
449 /// Return the buffer type for a given Value (tensor) after bufferization
450 /// without bufferizing any IR.
451 ///
452 /// Note: It should be sufficient to call `getBuffer()->getType()` in most
453 /// cases. However, when a buffer type should be predicted without modifying any
454 /// IR, this function can be used.
455 ///
456 /// This function is a wrapper around BufferizableOpInterface::getBufferType.
458  const BufferizationOptions &options);
459 
460 /// Return the buffer type for a given Value (tensor) after bufferization
461 /// without bufferizing any IR. If at any point during the type computation, the
462 /// type of a value in `fixedTypes` in required, the mapped type is used.
463 ///
464 /// Note: It should be sufficient to call `getBuffer()->getType()` in most
465 /// cases. However, when a buffer type should be predicted without modifying any
466 /// IR, this function can be used.
467 ///
468 /// This function is a wrapper around BufferizableOpInterface::getBufferType.
470 getBufferType(Value value, const BufferizationOptions &options,
471  const DenseMap<Value, BaseMemRefType> &fixedTypes);
472 
473 /// Replace an op with replacement values. The op is deleted. Tensor OpResults
474 /// must be replaced with memref values.
476  ValueRange values);
477 
478 /// Replace an op with a new op. The new op must have the same number of
479 /// results as the replaced op. The new op may not return any tensor values.
480 template <typename OpTy, typename... Args>
482  Args &&...args) {
483  auto newOp = rewriter.create<OpTy>(op->getLoc(), std::forward<Args>(args)...);
484  replaceOpWithBufferizedValues(rewriter, op, newOp->getResults());
485  return newOp;
486 }
487 
488 /// Return `true` if the buffer of given OpResult should be deallocated. This
489 /// function should be called during `BufferizableOpInterface::bufferize`
490 /// implementations that allocate a new buffer for the given OpResult.
491 bool shouldDeallocateOpResult(OpResult opResult,
492  const BufferizationOptions &options);
493 
494 /// Return a MemRefType to which the type of the given value can be bufferized.
495 ///
496 /// If possible, op bufferization implementations should not use this function
497 /// and instead infer precise memref types for tensor results by themselves.
498 ///
499 /// Unless a layout map was specified, `options.unknownTypeConverterFn`
500 /// determines what kind of layout map will be used. For best composability
501 /// (without copies), the fully dynamic layout map is used by default.
502 ///
503 /// Note: Canonicalization patterns could clean up layout maps and infer more
504 /// precise layout maps after bufferization. However, many possible
505 /// canonicalizations are currently not implemented.
506 BaseMemRefType getMemRefType(Value value, const BufferizationOptions &options,
507  MemRefLayoutAttrInterface layout = {},
508  Attribute memorySpace = nullptr);
509 
510 /// Return a MemRef type with fully dynamic layout. If the given tensor type
511 /// is unranked, return an unranked MemRef type.
512 BaseMemRefType
513 getMemRefTypeWithFullyDynamicLayout(TensorType tensorType,
514  Attribute memorySpace = nullptr);
515 
516 /// Return a MemRef type with a static identity layout (i.e., no layout map). If
517 /// the given tensor type is unranked, return an unranked MemRef type.
518 BaseMemRefType
519 getMemRefTypeWithStaticIdentityLayout(TensorType tensorType,
520  Attribute memorySpace = nullptr);
521 
522 /// Return the owner of the given value. In case of a BlockArgument that is the
523 /// owner of the block. In case of an OpResult that is the defining op.
524 Operation *getOwnerOfValue(Value value);
525 
526 /// Return the closest enclosing repetitive region around the given op.
527 Region *getEnclosingRepetitiveRegion(Operation *op,
528  const BufferizationOptions &options);
529 
530 /// Return the closest enclosing repetitive region around the place where the
531 /// given value is defined.
532 Region *getEnclosingRepetitiveRegion(Value value,
533  const BufferizationOptions &options);
534 
535 /// Return the closest enclosing repetitive region around the given block.
536 Region *getEnclosingRepetitiveRegion(Block *block,
537  const BufferizationOptions &options);
538 
539 namespace detail {
540 /// This is the default implementation of
541 /// BufferizableOpInterface::getBufferType. Should not be called from other
542 /// places.
545  const DenseMap<Value, BaseMemRefType> &fixedTypes);
546 
547 /// This is the default implementation of
548 /// BufferizableOpInterface::isRepetitiveRegion. Should not be called from other
549 /// places.
550 bool defaultIsRepetitiveRegion(BufferizableOpInterface bufferizableOp,
551  unsigned index);
552 } // namespace detail
553 
554 } // namespace bufferization
555 } // namespace mlir
556 
558 
559 //===----------------------------------------------------------------------===//
560 // Bufferization Interfaces
561 //===----------------------------------------------------------------------===//
562 
563 #include "mlir/Dialect/Bufferization/IR/BufferizableOpInterface.h.inc"
564 
565 #endif // MLIR_DIALECT_BUFFERIZATION_IR_BUFFERIZABLEOPINTERFACE_H_
static void copy(Location loc, Value dst, Value src, Value size, OpBuilder &builder)
Copies the given number of bytes from src to dst pointers.
static llvm::ManagedStatic< PassManagerOptions > options
#define MLIR_DECLARE_EXPLICIT_TYPE_ID(CLASS_NAME)
Definition: TypeID.h:249
Attributes are known-constant values of operations.
Definition: Attributes.h:25
This class provides a shared interface for ranked and unranked memref types.
Definition: BuiltinTypes.h:113
This class provides support for representing a failure result, or a valid value of type T.
Definition: LogicalResult.h:78
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition: Location.h:63
This class helps build Operations.
Definition: Builders.h:199
Operation * create(const OperationState &state)
Creates an operation given the fields represented as an OperationState.
Definition: Builders.cpp:422
This class represents an operand of an operation.
Definition: Value.h:255
This is a value defined by a result of an operation.
Definition: Value.h:450
Operation is the basic unit of execution within MLIR.
Definition: Operation.h:75
Location getLoc()
The source location the operation was defined or derived from.
Definition: Operation.h:198
result_range getResults()
Definition: Operation.h:376
This class coordinates the application of a rewrite on a set of IR, providing a way for clients to tr...
Definition: PatternMatch.h:399
This class provides an efficient unique identifier for a specific C++ type.
Definition: TypeID.h:104
This class provides an abstraction over the different types of ranges over Values.
Definition: ValueRange.h:350
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:93
AnalysisState provides a variety of helper functions for dealing with tensor values.
bool isValueRead(Value value) const
Return true if the given value is read by an op that bufferizes to a memory read.
virtual bool areAliasingBufferizedValues(Value v1, Value v2) const
Return true if v1 and v2 may bufferize to aliasing buffers.
virtual bool hasUndefinedContents(OpOperand *opOperand) const
Return true if the given tensor has undefined contents.
SetVector< Value > findValueInReverseUseDefChain(Value value, llvm::function_ref< bool(Value)> condition, bool followEquivalentOnly=false) const
Starting from value, follow the use-def chain in reverse, always selecting the aliasing OpOperands.
bool canOmitTensorCopy(OpOperand &opOperand) const
Return true if a copy can always be avoided when allocating a new tensor for the given OpOperand.
bool bufferizesToMemoryWrite(OpOperand &opOperand) const
Return true if opOperand bufferizes to a memory write.
virtual bool isInPlace(OpOperand &opOperand) const
Return true if the given OpResult has been decided to bufferize inplace.
bool bufferizesToAliasOnly(OpOperand &opOperand) const
Return true if opOperand does neither read nor write but bufferizes to an alias.
AnalysisState(const BufferizationOptions &options)
const BufferizationOptions & getOptions() const
Return a reference to the BufferizationOptions.
SetVector< Value > findLastPrecedingWrite(Value value) const
Find the Values of the last preceding write of a given Value.
virtual bool isTensorYielded(Value tensor) const
Return true if the given tensor (or an aliasing tensor) is yielded from the containing block.
bool bufferizesToMemoryRead(OpOperand &opOperand) const
Return true if opOperand bufferizes to a memory read.
static bool classof(const AnalysisState *base)
virtual bool areEquivalentBufferizedValues(Value v1, Value v2) const
Return true if v1 and v2 bufferize to equivalent buffers.
SmallVector< OpOperand * > getAliasingOpOperand(OpResult result) const
Determine which OpOperand* will alias with result if the op is bufferized in place.
SmallVector< OpResult > getAliasingOpResult(OpOperand &opOperand) const
Determine which OpResult will alias with opOperand if the op is bufferized in place.
AnalysisState(const AnalysisState &)=delete
void denyOperation()
Deny the given ops.
void allowOperation(StringRef opName)
Allow the given op.
void denyOperation(StringRef opName)
Deny the given op.
void denyDialect()
Deny the given dialects.
void allowOperation(Entry::FilterFn fn)
Allow ops that are matched by fn.
void allowDialect()
Allow the given dialects.
void allowDialect(StringRef dialectNamespace)
Allow the given dialect.
void denyOperation(Entry::FilterFn fn)
Deny ops that are matched by fn.
bool isOpAllowed(Operation *op) const
Return whether the op is allowed or not.
void allowOperation()
Allow the given ops.
FailureOr< BaseMemRefType > defaultGetBufferType(Value value, const BufferizationOptions &options, const DenseMap< Value, BaseMemRefType > &fixedTypes)
This is the default implementation of BufferizableOpInterface::getBufferType.
bool defaultIsRepetitiveRegion(BufferizableOpInterface bufferizableOp, unsigned index)
This is the default implementation of BufferizableOpInterface::isRepetitiveRegion.
void replaceOpWithBufferizedValues(RewriterBase &rewriter, Operation *op, ValueRange values)
Replace an op with replacement values.
BaseMemRefType getMemRefTypeWithStaticIdentityLayout(TensorType tensorType, Attribute memorySpace=nullptr)
Return a MemRef type with a static identity layout (i.e., no layout map).
Operation * getOwnerOfValue(Value value)
Return the owner of the given value.
bool allocationDoesNotEscape(OpResult opResult)
Return true if the allocation of the given op is guaranteed to not escape the containing block.
BaseMemRefType getMemRefType(Value value, const BufferizationOptions &options, MemRefLayoutAttrInterface layout={}, Attribute memorySpace=nullptr)
Return a MemRefType to which the type of the given value can be bufferized.
bool shouldDeallocateOpResult(OpResult opResult, const BufferizationOptions &options)
Return true if the buffer of given OpResult should be deallocated.
Region * getEnclosingRepetitiveRegion(Operation *op, const BufferizationOptions &options)
Return the closest enclosing repetitive region around the given op.
FailureOr< Value > allocateTensorForShapedValue(OpBuilder &b, Location loc, Value shapedValue, bool escape, const BufferizationOptions &options, bool copy=true)
Create an AllocTensorOp for the given shaped value (memref or tensor).
OpTy replaceOpWithNewBufferizedOp(RewriterBase &rewriter, Operation *op, Args &&...args)
Replace an op with a new op.
bool isFunctionArgument(Value value)
Return true if the given value is a BlockArgument of a func::FuncOp.
FailureOr< BaseMemRefType > getBufferType(Value value, const BufferizationOptions &options)
Return the buffer type for a given Value (tensor) after bufferization without bufferizing any IR.
FailureOr< Value > getBuffer(RewriterBase &rewriter, Value value, const BufferizationOptions &options)
Lookup the buffer for the given value.
BaseMemRefType getMemRefTypeWithFullyDynamicLayout(TensorType tensorType, Attribute memorySpace=nullptr)
Return a MemRef type with fully dynamic layout.
BufferRelation
Specify fine-grain relationship between buffers to enable more analysis.
Include the generated interface declarations.
This class represents an efficient way to signal success or failure.
Definition: LogicalResult.h:26
Options for BufferizableOpInterface-based bufferization.
bool createDeallocs
Specifies whether dealloc ops should be generated along with alloc ops.
bool copyBeforeWrite
If set to true, the analysis is skipped.
unsigned analysisFuzzerSeed
Seed for the analysis fuzzer.
std::function< LogicalResult(OpBuilder &, Location, Value)> DeallocationFn
Deallocator function: Deallocate a buffer that was allocated with AllocatorFn.
std::function< void(AnalysisState &)> AnalysisStateInitFn
Initializer function for analysis state.
bool allowUnknownOps
Specifies whether not bufferizable ops are allowed in the input.
BufferizableOpInterface dynCastBufferizableOp(Operation *op) const
Try to cast the given op to BufferizableOpInterface if the op is allow listed.
std::function< BaseMemRefType(Value, Attribute memorySpace, const BufferizationOptions &)> UnknownTypeConverterFn
Tensor -> MemRef type converter.
LayoutMapOption functionBoundaryTypeConversion
This flag controls buffer types on function signatures.
unsigned int bufferAlignment
Buffer alignment for new memory allocations.
bool printConflicts
If set to true, the IR is annotated with details about RaW conflicts.
std::optional< AllocationFn > allocationFn
Helper functions for allocation, deallocation, memory copying.
bool testAnalysisOnly
If set to true, does not modify the IR apart from adding attributes (for checking the results of the ...
bool enforceAliasingInvariants
Certain ops have aliasing OpOperand/OpResult invariants (e.g., scf.for).
OpFilter opFilter
A filter that specifies which ops should be bufferized and which ops should be ignored.
bool isOpAllowed(Operation *op) const
Return true if the given op should be bufferized.
std::optional< DeallocationFn > deallocationFn
std::optional< Attribute > defaultMemorySpace
The default memory space that should be used when it cannot be inferred from the context.
UnknownTypeConverterFn unknownTypeConverterFn
Type converter from tensors to memrefs.
bool bufferizeFunctionBoundaries
Specifies whether function boundaries (ops in the func dialect) should be bufferized or not.
std::function< LogicalResult(OpBuilder &, Location, Value, Value)> MemCpyFn
Memcpy function: Generate a memcpy between two buffers.
LogicalResult createDealloc(OpBuilder &b, Location loc, Value allocatedBuffer) const
Creates a memref deallocation.
FailureOr< Value > createAlloc(OpBuilder &b, Location loc, MemRefType type, ValueRange dynShape) const
Create a memref allocation with the given type and dynamic extents.
std::function< FailureOr< Value >(OpBuilder &, Location, MemRefType, ValueRange, unsigned int)> AllocationFn
Allocator function: Generate a memref allocation with the given type, dynamic extents and alignment.
LogicalResult createMemCpy(OpBuilder &b, Location loc, Value from, Value to) const
Creates a memcpy between two given buffers.
SmallVector< AnalysisStateInitFn > stateInitializers
Initializer functions for analysis state.
FilterType
Filter type: A filter can either be a DENY filter or an ALLOW filter.
std::function< bool(Operation *)> FilterFn
If the filter function evaluates to true, the filter matches.