MLIR  19.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/DenseMapInfoVariant.h"
16 #include "llvm/ADT/SetVector.h"
17 #include <optional>
18 
19 #include "mlir/Dialect/Bufferization/IR/BufferizationEnums.h.inc"
20 
21 namespace mlir {
22 class OpBuilder;
23 namespace func {
24 class FuncOp;
25 }
26 
27 namespace bufferization {
28 
29 class AnalysisState;
30 class BufferizableOpInterface;
31 
32 /// Specifies a fine-grain relationship between buffers to enable more analysis.
33 enum class BufferRelation {
34  Unknown,
35  // TODO: ResultContainsOperand,
36  // TODO: OperandContainsResult,
38 };
39 
40 /// A maybe aliasing OpOperand. If `isDefinite` is `true`, the OpOperand is
41 /// guaranteed to alias at runtime.
44  bool isDefinite = true)
46 
49  bool isDefinite;
50 };
51 
52 /// A maybe aliasing Value. If `isDefinite` is `true`, the Value is guaranteed
53 /// to alias at runtime.
54 struct AliasingValue {
57 
60  bool isDefinite;
61 };
62 
63 template <typename T> class AliasList {
64 public:
65  /// Create an empty list of aliases.
66  AliasList() = default;
67 
68  /// Create a list of aliases.
69  AliasList(std::initializer_list<T> elems) {
70  for (T alias : elems)
71  addAlias(alias);
72  }
73 
74  /// Create a list of aliases.
75  AliasList(SmallVector<T> &&aliases) : aliases(std::move(aliases)) {}
76 
77  ArrayRef<T> getAliases() const { return aliases; }
78 
79  size_t getNumAliases() const { return aliases.size(); }
80 
81  void addAlias(T alias) { aliases.push_back(alias); }
82 
83  auto begin() const { return aliases.begin(); }
84  auto end() const { return aliases.end(); }
85 
86 private:
87  /// The list of aliases.
88  SmallVector<T> aliases;
89 };
90 
91 /// A list of possible aliasing OpOperands. This list models the runtime
92 /// aliasing relationship for a Value.
94 
95 /// A list of possible aliasing Values. This list models the runtime aliasing
96 /// relationship for an OpOperand.
98 
99 class OpFilter {
100 public:
101  /// An op filter entry. Filters can be used to specify which ops should be
102  /// processed by the bufferization.
103  struct Entry {
104  /// If the filter function evaluates to `true`, the filter matches.
105  using FilterFn = std::function<bool(Operation *)>;
106 
107  /// Filter type: A filter can either be a DENY filter or an ALLOW filter.
108  enum FilterType : int8_t { DENY = 0, ALLOW = 1 };
109 
112  };
113 
114  /// Return whether the op is allowed or not.
115  ///
116  /// If the filter does not have an ALLOW rule, ops are allowed by default,
117  /// unless they are explicitly marked as DENY. If the filter has at least one
118  /// ALLOW rule, ops are denied by default and only allowed if they match
119  /// an ALLOW rule and no DENY rule.
120  bool isOpAllowed(Operation *op) const;
121 
122  /// Allow the given dialects.
123  ///
124  /// This function adds one or multiple ALLOW entries.
125  template <typename... DialectTs>
126  void allowDialect() {
127  // The following expands a call to allowDialectImpl for each dialect
128  // in 'DialectTs'.
129  (allowDialectImpl<DialectTs>(), ...);
130  }
131 
132  /// Deny the given dialects.
133  ///
134  /// This function adds one or multiple DENY entries.
135  template <typename... DialectTs>
136  void denyDialect() {
137  (denyDialectImpl<DialectTs>(), ...);
138  }
139 
140  /// Allow the given dialect.
141  ///
142  /// This function adds an ALLOW entry.
143  void allowDialect(StringRef dialectNamespace) {
144  Entry::FilterFn filterFn = [=](Operation *op) {
145  return op->getName().getDialectNamespace() == dialectNamespace;
146  };
147  entries.push_back(Entry{filterFn, Entry::FilterType::ALLOW});
148  }
149 
150  /// Deny the given dialect.
151  ///
152  /// This function adds a DENY entry.
153  void denyDialect(StringRef dialectNamespace) {
154  Entry::FilterFn filterFn = [=](Operation *op) {
155  return op->getDialect()->getNamespace() == dialectNamespace;
156  };
157  entries.push_back(Entry{filterFn, Entry::FilterType::DENY});
158  }
159 
160  /// Allow the given ops.
161  ///
162  /// This function adds one or multiple ALLOW entries.
163  template <typename... OpTys>
164  void allowOperation() {
165  (allowOperationImpl<OpTys>(), ...);
166  }
167 
168  /// Deny the given ops.
169  ///
170  /// This function adds one or multiple DENY entries.
171  template <typename... OpTys>
172  void denyOperation() {
173  (denyOperationImpl<OpTys>(), ...);
174  }
175 
176  /// Allow the given op.
177  ///
178  /// This function adds an ALLOW entry.
179  void allowOperation(StringRef opName) {
180  Entry::FilterFn filterFn = [=](Operation *op) {
181  return op->getName().getStringRef() == opName;
182  };
183  allowOperation(filterFn);
184  }
185 
186  /// Deny the given op.
187  ///
188  /// This function adds a DENY entry.
189  void denyOperation(StringRef opName) {
190  Entry::FilterFn filterFn = [=](Operation *op) {
191  return op->getName().getStringRef() == opName;
192  };
193  denyOperation(filterFn);
194  }
195 
196  /// Allow ops that are matched by `fn`.
197  ///
198  /// This function adds an ALLOW entry.
200  entries.push_back(Entry{fn, Entry::FilterType::ALLOW});
201  }
202 
203  /// Deny ops that are matched by `fn`.
204  ///
205  /// This function adds a DENY entry.
207  entries.push_back(Entry{fn, Entry::FilterType::DENY});
208  }
209 
210 private:
211  /// Return `true` if the filter has at least one ALLOW rule.
212  bool hasAllowRule() const {
213  for (const Entry &e : entries)
214  if (e.type == Entry::FilterType::ALLOW)
215  return true;
216  return false;
217  }
218 
219  /// Allow a dialect.
220  template <typename DialectT>
221  void allowDialectImpl() {
222  allowDialect(DialectT::getDialectNamespace());
223  }
224 
225  /// Deny a dialect.
226  template <typename DialectT>
227  void denyDialectImpl() {
228  denyDialect(DialectT::getDialectNamespace());
229  }
230 
231  /// Allow an op.
232  template <typename OpTy>
233  void allowOperationImpl() {
234  allowOperation(OpTy::getOperationName());
235  }
236 
237  /// Deny an op.
238  template <typename OpTy>
239  void denyOperationImpl() {
240  denyOperation(OpTy::getOperationName());
241  }
242 
243  /// A list of filter entries that determine whether an op should be allowed or
244  /// denied. If the filter has an ALLOW rule, only ops that are allowed and not
245  /// denied are allowed. If the filter does not have an ALLOW rule, only ops
246  /// that are not denied are allowed.
247  SmallVector<Entry> entries;
248 };
249 
250 /// Options for BufferizableOpInterface-based bufferization.
252  /// Allocator function: Generate a memref allocation with the given type,
253  /// dynamic extents and alignment.
254  using AllocationFn = std::function<FailureOr<Value>(
255  OpBuilder &, Location, MemRefType, ValueRange, unsigned int)>;
256  /// Memcpy function: Generate a memcpy between two buffers.
257  using MemCpyFn =
258  std::function<LogicalResult(OpBuilder &, Location, Value, Value)>;
259  /// Initializer function for analysis state.
260  using AnalysisStateInitFn = std::function<void(AnalysisState &)>;
261  /// Tensor -> MemRef type converter.
262  /// Parameters: Value, memory space, func op, bufferization options
264  std::function<BaseMemRefType(TensorType, Attribute memorySpace,
265  func::FuncOp, const BufferizationOptions &)>;
266  /// Tensor -> MemRef type converter.
267  /// Parameters: Value, memory space, bufferization options
268  using UnknownTypeConverterFn = std::function<BaseMemRefType(
269  Value, Attribute memorySpace, const BufferizationOptions &)>;
270  // Produce a MemorySpace attribute from a tensor type
272  std::function<std::optional<Attribute>(TensorType t)>;
273 
275 
276  /// Try to cast the given op to BufferizableOpInterface if the op is allow
277  /// listed.
278  BufferizableOpInterface dynCastBufferizableOp(Operation *op) const;
279 
280  /// Try to cast the given value to BufferizableOpInterface if the op is allow
281  /// listed.
282  BufferizableOpInterface dynCastBufferizableOp(Value value) const;
283 
284  /// A filter that specifies which ops should be bufferized and which ops
285  /// should be ignored.
287 
288  /// Return `true` if the given op should be bufferized.
289  bool isOpAllowed(Operation *op) const;
290 
291  /// Helper functions for allocation and memory copying.
292  std::optional<AllocationFn> allocationFn;
293  std::optional<MemCpyFn> memCpyFn;
294 
295  /// Create a memref allocation with the given type and dynamic extents.
296  FailureOr<Value> createAlloc(OpBuilder &b, Location loc, MemRefType type,
297  ValueRange dynShape) const;
298 
299  /// Creates a memcpy between two given buffers.
301  Value to) const;
302 
303  /// Specifies whether not bufferizable ops are allowed in the input. If so,
304  /// bufferization.to_memref and bufferization.to_tensor ops are inserted at
305  /// the boundaries.
306  bool allowUnknownOps = false;
307 
308  /// Specifies whether function boundaries (ops in the func dialect) should be
309  /// bufferized or not.
311 
312  /// Certain ops have aliasing OpOperand/OpResult invariants (e.g., scf.for).
313  /// If this flag is set to `false`, those invariants are no longer enforced
314  /// with buffer copies.
315  ///
316  /// Note: Deactivating this flag can lead to incorrect bufferization results
317  /// when used incorrectly. This flag is useful with
318  /// `AlwaysCopyAnalysisState` which bufferizes all writing tensor
319  /// OpOperands out-of-place.
321 
322  /// This function controls buffer types on function signatures. Sets
323  /// `functionArgTypeConverterFn` and `inferFunctionResultLayout` accordingly.
324  ///
325  /// * InferLayoutMap: All function parameter types have a fully dynamic layout
326  /// map, but function result types are inferred from the body of the
327  /// function.
328  /// * FullyDynamicLayoutMap: All function parameter types and result types
329  /// have a fully dynamic layout map. This option is most efficient because
330  /// any layout map can be casted to a fully dynamic one.
331  /// * IdentityLayoutMap: All function parameter types and result types have a
332  /// static identity layout (i.e., no layout map). This option may introduce
333  /// additional buffer allocs and copies because layout maps cannot be casted
334  /// away.
335  ///
336  /// Note: Inferred layout maps may not be desireable when interacting with
337  /// external functions, because the generated function signatures will be less
338  /// predictable.
339  void setFunctionBoundaryTypeConversion(LayoutMapOption layoutMapOption);
340 
341  /// Type converter from tensors to memrefs. This type converter is used to
342  /// determine bufferized function argument types. By default, a type
343  /// converter that returns a memref type with a fully dynamic layout map is
344  /// used.
345  ///
346  /// If `bufferizeFunctionBoundaries` is not set, this function isn't used.
348 
349  /// If true, function result types are inferred from the body of the function.
350  /// Otherwise, function result type is determined by
351  /// `functionArgTypeConverterFn`.
352  ///
353  /// If `bufferizeFunctionBoundaries` is not set, this flag has no effect.
355 
356  /// Type converter from tensors to memrefs. This type converter is used if no
357  /// memref type could be inferred during bufferization. By default, a type
358  /// converter that returns a memref type with a fully dynamic layout map is
359  /// used.
361 
362  // Use during type conversion to determine the memory space for memref based
363  // on the original tensor type if the memory space cannot be inferred.
364  // Returning std::nullopt will cause bufferization to fail (useful to indicate
365  // failure to determine memory space for a tensor type).
367  [](TensorType t) -> std::optional<Attribute> { return Attribute(); };
368 
369  /// If set to `true`, the analysis is skipped. A buffer is copied before every
370  /// write. This flag cannot be used together with `testAnalysisOnly = true`.
371  bool copyBeforeWrite = false;
372 
373  /// If set to `true`, does not modify the IR apart from adding attributes (for
374  /// checking the results of the analysis) and post analysis steps.
375  bool testAnalysisOnly = false;
376 
377  /// If set to `true`, the IR is annotated with details about RaW conflicts.
378  /// For debugging only. Should be used together with `testAnalysisOnly`.
379  bool printConflicts = false;
380 
381  /// Buffer alignment for new memory allocations.
382  unsigned int bufferAlignment = 64;
383 
384  /// Initializer functions for analysis state. These can be used to
385  /// initialize dialect-specific analysis state.
387 };
388 
389 /// Traversal parameters for `findValueInReverseUseDefChain`.
391  /// Specifies if leaves (that do not have further OpOperands to follow)
392  /// should be returned even if they do not match the specified filter.
393  bool alwaysIncludeLeaves = true;
394 
395  /// Specifies whether out-of-place/undecided OpOperands should be followed.
396  bool followInPlaceOnly = false;
397 
398  /// Specifies whether non-equivalent OpOperands should be followed.
399  bool followEquivalentOnly = false;
400 
401  /// Specifies whether unknown/non-bufferizable/ops not included in the
402  /// OpFilter of BufferizationOptions should be followed.
403  bool followUnknownOps = false;
404 
405  /// Specifies whether OpOperands with a different type that are not the result
406  /// of a CastOpInterface op should be followed.
408 
409  /// Specifies whether already visited values should be visited again.
410  /// (Note: This can result in infinite looping.)
412 };
413 
414 /// AnalysisState provides a variety of helper functions for dealing with
415 /// tensor values.
417 public:
418  /// Determine which OpOperand* will alias with `value` if the op is
419  /// bufferized in place. Return all tensor OpOperand* if the op is not
420  /// bufferizable.
422 
423  /// Determine which Value will alias with `opOperand` if the op is bufferized
424  /// in place. Return all tensor Values if the op is not bufferizable.
426 
427  /// Return true if `opOperand` bufferizes to a memory read. Return `true` if
428  /// the op is not bufferizable.
429  bool bufferizesToMemoryRead(OpOperand &opOperand) const;
430 
431  /// Return true if `opOperand` bufferizes to a memory write. Return true` if
432  /// the op is not bufferizable.
433  bool bufferizesToMemoryWrite(OpOperand &opOperand) const;
434 
435  /// Return true if the given `value` bufferizes to a memory write. Return
436  /// true if the value is a block argument. Return `true` if the defining op is
437  /// not bufferizable. Otherwise, consult the BufferizableOpInterface.
438  bool bufferizesToMemoryWrite(Value value) const;
439 
440  /// Return true if `opOperand` does neither read nor write but bufferizes to
441  /// an alias. Return false if the op is not bufferizable.
442  bool bufferizesToAliasOnly(OpOperand &opOperand) const;
443 
444  /// Return true if a copy can always be avoided when allocating a new tensor
445  /// for the given OpOperand.
446  bool canOmitTensorCopy(OpOperand &opOperand) const;
447 
448  /// Return true if the given value is read by an op that bufferizes to a
449  /// memory read. Also takes into account ops that create an alias but do not
450  /// read by themselves (e.g., ExtractSliceOp).
451  bool isValueRead(Value value) const;
452 
453  /// Starting from `value`, follow the use-def chain in reverse, always
454  /// selecting the aliasing OpOperands. Find and return Values for which
455  /// `condition` evaluates to true. OpOperands of such matching Values are not
456  /// traversed any further.
457  ///
458  /// When reaching the end of a chain, also return the last Value of that
459  /// chain if `config.alwaysIncludeLeaves` is set.
460  ///
461  /// Example:
462  ///
463  /// 8
464  /// |
465  /// 6* 7* +-----+----+
466  /// | | | |
467  /// 2* 3 4* 5
468  /// | | | |
469  /// +----------+----------+----------+
470  /// |
471  /// 1
472  ///
473  /// In the above example, Values with a star satisfy the condition. When
474  /// starting the traversal from Value 1, the resulting SetVector is:
475  /// { 2, 7, 8, 5 }
476  ///
477  /// Additional stopping conditions for the traversal can be specified in
478  /// `config`.
480  Value value, llvm::function_ref<bool(Value)> condition,
481  TraversalConfig config = TraversalConfig()) const;
482 
483  /// Find the values that may define the contents of the given value at
484  /// runtime. A block argument is always a definition. An OpResult is a
485  /// definition if it bufferizes to memory write. If it does not bufferize to
486  /// a memory write but has aliasing operands, we continue the lookup on these
487  /// values.
488  ///
489  /// Example: %r = tensor.insert %f into %t[%c0] : tensor<?xf32>
490  /// findDefinitions(%r) = {%r} because %r bufferizes to memory write.
491  ///
492  /// Example: %r = tensor.empty() : tensor<10xf32>
493  /// findDefinitions(%r) = {} because tensor.empty does not the define the
494  /// contents of its result (i.e., it does not bufferize to a memory write)
495  /// and it has no aliasing OpOperands.
496  ///
497  /// Example:
498  /// %a = arith.constant ... : tensor<10xf32>
499  /// %b1 = tensor.insert %f into %t : tensor<50xf32>
500  /// %b2 = tensor.extract_slice %b1[0][10][1] : tensor<50xf32> tensor<10xf32>
501  /// %r = arith.select %cond, %a, %b : tensor<10xf32>
502  /// findDefinitions(%r) = {%a, %b1}. %r and %b2 are skipped (lookup continues
503  /// in the operands) because their defining ops do not define the contents of
504  /// the tensor.
505  ///
506  /// Example:
507  /// %a = tensor.empty() : tensor<10xf32>
508  /// %b = arith.constant ... : tensor<10xf32>
509  /// %r = arith.select %cond, %a, %b : tensor<10xf32>
510  /// findDefinitions(%r) = {%b}. %a is excluded because it does not define the
511  /// contents of the tensor.
512  ///
513  /// Note: OpResults of unknown ops are handled conservatively and assumed to
514  /// be definitions.
516 
517  /// Return `true` if the given OpResult has been decided to bufferize inplace.
518  virtual bool isInPlace(OpOperand &opOperand) const;
519 
520  /// Return true if `v1` and `v2` bufferize to equivalent buffers.
521  virtual bool areEquivalentBufferizedValues(Value v1, Value v2) const;
522 
523  /// Return true if `v1` and `v2` may bufferize to aliasing buffers.
524  virtual bool areAliasingBufferizedValues(Value v1, Value v2) const;
525 
526  /// Return `true` if the given tensor has undefined contents.
527  virtual bool hasUndefinedContents(OpOperand *opOperand) const;
528 
529  /// Return a reference to the BufferizationOptions.
530  const BufferizationOptions &getOptions() const { return options; }
531 
532  AnalysisState(const BufferizationOptions &options);
533 
534  // AnalysisState should be passed as a reference.
535  AnalysisState(const AnalysisState &) = delete;
536 
537  virtual ~AnalysisState() = default;
538 
539  static bool classof(const AnalysisState *base) { return true; }
540 
541  TypeID getType() const { return type; }
542 
543  /// Return the closest enclosing repetitive region around the given op.
545  const BufferizationOptions &options);
546 
547  /// Return the closest enclosing repetitive region around the place where the
548  /// given value is defined.
550  const BufferizationOptions &options);
551 
552  /// Return the closest enclosing repetitive region around the given block.
554  const BufferizationOptions &options);
555 
556  virtual void resetCache();
557 
558 protected:
559  AnalysisState(const BufferizationOptions &options, TypeID type);
560 
561 private:
562  /// A reference to current bufferization options.
563  const BufferizationOptions &options;
564 
565  /// The type of analysis.
566  TypeID type;
567 
568  /// Cache containing closest ancestor repetitive Region.
570  enclosingRepetitiveRegionCache;
571 };
572 
573 /// Create an AllocTensorOp for the given shaped value (memref or tensor).
574 /// If `copy` is set, the shaped value is copied. Otherwise, a tensor with
575 /// undefined contents is allocated.
578  const BufferizationOptions &options,
579  bool copy = true);
580 
581 /// Lookup the buffer for the given value. If the value was not bufferized
582 /// yet, wrap it in a ToMemrefOp. Otherwise, it is the result of a ToTensorOp,
583 /// from which the memref operand is returned.
585  const BufferizationOptions &options);
586 
587 /// Return the buffer type for a given Value (tensor) after bufferization
588 /// without bufferizing any IR.
589 ///
590 /// Note: It should be sufficient to call `getBuffer()->getType()` in most
591 /// cases. However, when a buffer type should be predicted without modifying any
592 /// IR, this function can be used.
593 ///
594 /// This function is a wrapper around BufferizableOpInterface::getBufferType.
596  const BufferizationOptions &options);
597 
598 /// Return the buffer type for a given Value (tensor) after bufferization
599 /// without bufferizing any IR. This function (and not the other overload
600 /// without `invocationStack`) can be used from `getBufferType` implementations
601 /// of the `BufferizableOpInterface`.
602 ///
603 /// Note: It should be sufficient to call `getBuffer()->getType()` in most
604 /// cases. However, when a buffer type should be predicted without modifying any
605 /// IR, this function can be used.
606 ///
607 /// This function is a wrapper around `BufferizableOpInterface::getBufferType`.
609  const BufferizationOptions &options,
610  SmallVector<Value> &invocationStack);
611 
612 /// Return "true" if the given op has tensor semantics and should be bufferized.
613 /// If the op is bufferizable, the BufferizableOpInterface is queried.
614 /// Otherwise, an op has tensor semantics if it has tensor operands, tensor
615 /// op results and/or tensor block arguments.
616 bool hasTensorSemantics(Operation *op);
617 
618 /// Replace an op with replacement values. The op is deleted. Tensor OpResults
619 /// must be replaced with memref values.
621  ValueRange values);
622 
623 /// Replace an op with a new op. The new op must have the same number of
624 /// results as the replaced op. The new op may not return any tensor values.
625 template <typename OpTy, typename... Args>
627  Args &&...args) {
628  auto newOp = rewriter.create<OpTy>(op->getLoc(), std::forward<Args>(args)...);
629  replaceOpWithBufferizedValues(rewriter, op, newOp->getResults());
630  return newOp;
631 }
632 
633 /// Return a MemRefType to which the type of the given value can be bufferized.
634 ///
635 /// If possible, op bufferization implementations should not use this function
636 /// and instead infer precise memref types for tensor results by themselves.
637 ///
638 /// Unless a layout map was specified, `options.unknownTypeConverterFn`
639 /// determines what kind of layout map will be used. For best composability
640 /// (without copies), the fully dynamic layout map is used by default.
641 ///
642 /// Note: Canonicalization patterns could clean up layout maps and infer more
643 /// precise layout maps after bufferization. However, many possible
644 /// canonicalizations are currently not implemented.
645 BaseMemRefType getMemRefType(Value value, const BufferizationOptions &options,
646  MemRefLayoutAttrInterface layout = {},
647  Attribute memorySpace = nullptr);
648 
649 /// Return a MemRef type with fully dynamic layout. If the given tensor type
650 /// is unranked, return an unranked MemRef type.
651 BaseMemRefType
652 getMemRefTypeWithFullyDynamicLayout(TensorType tensorType,
653  Attribute memorySpace = nullptr);
654 
655 /// Return a MemRef type with a static identity layout (i.e., no layout map). If
656 /// the given tensor type is unranked, return an unranked MemRef type.
657 BaseMemRefType
658 getMemRefTypeWithStaticIdentityLayout(TensorType tensorType,
659  Attribute memorySpace = nullptr);
660 
661 /// Return the owner of the given value. In case of a BlockArgument that is the
662 /// owner of the block. In case of an OpResult that is the defining op.
663 Operation *getOwnerOfValue(Value value);
664 
665 /// Assuming that the given region is repetitive, find the next enclosing
666 /// repetitive region.
667 Region *getNextEnclosingRepetitiveRegion(Region *region,
668  const BufferizationOptions &options);
669 
670 /// If `region` is a parallel region, return `region`. Otherwise, find the first
671 /// enclosing parallel region of `region`. If there is no such region, return
672 /// "nullptr".
673 ///
674 /// Note: Whether a region is parallel or sequential is queried from the
675 /// `BufferizableOpInterface`.
676 Region *getParallelRegion(Region *region, const BufferizationOptions &options);
677 
678 namespace detail {
679 /// This is the default implementation of
680 /// BufferizableOpInterface::getAliasingOpOperands. Should not be called from
681 /// other places.
683  const AnalysisState &state);
684 
685 /// This is the default implementation of
686 /// BufferizableOpInterface::getBufferType. Should not be called from other
687 /// places.
690  SmallVector<Value> &invocationStack);
691 
692 /// This is the default implementation of
693 /// BufferizableOpInterface::resultBufferizesToMemoryWrite. Should not be called
694 /// from other places.
696  const AnalysisState &state);
697 
698 /// This is the default implementation of
699 /// BufferizableOpInterface::isRepetitiveRegion. Should not be called from other
700 /// places.
701 bool defaultIsRepetitiveRegion(BufferizableOpInterface bufferizableOp,
702  unsigned index);
703 
704 /// This is the default implementation of getAliasingOpOperands in case the
705 /// defining op does not implement the BufferizableOpInterface.
707 
708 /// This is the default implementation of getAliasingValues in case the owner
709 /// op does not implement the BufferizableOpInterface.
711 
712 /// This is the default implementation of
713 /// BufferizableOpInterface::hasTensorSemantics
715 } // namespace detail
716 
717 } // namespace bufferization
718 } // namespace mlir
719 
721 
722 //===----------------------------------------------------------------------===//
723 // Bufferization Interfaces
724 //===----------------------------------------------------------------------===//
725 
726 #include "mlir/Dialect/Bufferization/IR/BufferizableOpInterface.h.inc"
727 
728 #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:138
Block represents an ordered list of Operations.
Definition: Block.h:30
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:209
Operation * create(const OperationState &state)
Creates an operation given the fields represented as an OperationState.
Definition: Builders.cpp:464
This class represents an operand of an operation.
Definition: Value.h:267
This is a value defined by a result of an operation.
Definition: Value.h:457
Operation is the basic unit of execution within MLIR.
Definition: Operation.h:88
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Definition: Region.h:26
This class coordinates the application of a rewrite on a set of IR, providing a way for clients to tr...
Definition: PatternMatch.h:400
Tensor types represent multi-dimensional arrays, and have two variants: RankedTensorType and Unranked...
Definition: BuiltinTypes.h:91
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:381
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:96
AliasList(std::initializer_list< T > elems)
Create a list of aliases.
AliasList()=default
Create an empty list of aliases.
AliasList(SmallVector< T > &&aliases)
Create a list of aliases.
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.
AliasingValueList getAliasingValues(OpOperand &opOperand) const
Determine which Value will alias with opOperand if the op is bufferized in place.
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.
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.
AliasingOpOperandList getAliasingOpOperands(Value value) const
Determine which OpOperand* will alias with value if the op is bufferized in place.
AnalysisState(const BufferizationOptions &options)
Region * getEnclosingRepetitiveRegion(Operation *op, const BufferizationOptions &options)
Return the closest enclosing repetitive region around the given op.
const BufferizationOptions & getOptions() const
Return a reference to the BufferizationOptions.
bool bufferizesToMemoryRead(OpOperand &opOperand) const
Return true if opOperand bufferizes to a memory read.
SetVector< Value > findValueInReverseUseDefChain(Value value, llvm::function_ref< bool(Value)> condition, TraversalConfig config=TraversalConfig()) const
Starting from value, follow the use-def chain in reverse, always selecting the aliasing OpOperands.
SetVector< Value > findDefinitions(Value value) const
Find the values that may define the contents of the given value at runtime.
static bool classof(const AnalysisState *base)
virtual bool areEquivalentBufferizedValues(Value v1, Value v2) const
Return true if v1 and v2 bufferize to equivalent buffers.
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.
void denyDialect(StringRef dialectNamespace)
Deny the given dialect.
AliasingOpOperandList defaultGetAliasingOpOperands(Value value, const AnalysisState &state)
This is the default implementation of BufferizableOpInterface::getAliasingOpOperands.
bool defaultResultBufferizesToMemoryWrite(OpResult opResult, const AnalysisState &state)
This is the default implementation of BufferizableOpInterface::resultBufferizesToMemoryWrite.
AliasingValueList unknownGetAliasingValues(OpOperand &opOperand)
This is the default implementation of getAliasingValues in case the owner op does not implement the B...
bool defaultIsRepetitiveRegion(BufferizableOpInterface bufferizableOp, unsigned index)
This is the default implementation of BufferizableOpInterface::isRepetitiveRegion.
AliasingOpOperandList unknownGetAliasingOpOperands(Value value)
This is the default implementation of getAliasingOpOperands in case the defining op does not implemen...
bool defaultHasTensorSemantics(Operation *op)
This is the default implementation of BufferizableOpInterface::hasTensorSemantics.
FailureOr< BaseMemRefType > defaultGetBufferType(Value value, const BufferizationOptions &options, SmallVector< Value > &invocationStack)
This is the default implementation of BufferizableOpInterface::getBufferType.
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.
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.
Region * getParallelRegion(Region *region, const BufferizationOptions &options)
If region is a parallel region, return region.
Region * getNextEnclosingRepetitiveRegion(Region *region, const BufferizationOptions &options)
Assuming that the given region is repetitive, find the next enclosing repetitive region.
OpTy replaceOpWithNewBufferizedOp(RewriterBase &rewriter, Operation *op, Args &&...args)
Replace an op with a new op.
FailureOr< Value > allocateTensorForShapedValue(OpBuilder &b, Location loc, Value shapedValue, const BufferizationOptions &options, bool copy=true)
Create an AllocTensorOp for the given shaped value (memref or tensor).
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.
bool hasTensorSemantics(Operation *op)
Return "true" if the given op has tensor semantics and should be bufferized.
BufferRelation
Specifies a 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
AliasingOpOperand(OpOperand *opOperand, BufferRelation relation, bool isDefinite=true)
AliasingValue(Value value, BufferRelation relation, bool isDefinite=true)
Options for BufferizableOpInterface-based bufferization.
bool copyBeforeWrite
If set to true, the analysis is skipped.
std::function< void(AnalysisState &)> AnalysisStateInitFn
Initializer function for analysis state.
void setFunctionBoundaryTypeConversion(LayoutMapOption layoutMapOption)
This function controls buffer types on function signatures.
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.
bool inferFunctionResultLayout
If true, function result types are inferred from the body of the function.
std::function< BaseMemRefType(Value, Attribute memorySpace, const BufferizationOptions &)> UnknownTypeConverterFn
Tensor -> MemRef type converter.
unsigned int bufferAlignment
Buffer alignment for new memory allocations.
FunctionArgTypeConverterFn functionArgTypeConverterFn
Type converter from tensors to memrefs.
bool printConflicts
If set to true, the IR is annotated with details about RaW conflicts.
std::function< std::optional< Attribute >(TensorType t)> DefaultMemorySpaceFn
std::function< BaseMemRefType(TensorType, Attribute memorySpace, func::FuncOp, const BufferizationOptions &)> FunctionArgTypeConverterFn
Tensor -> MemRef type converter.
std::optional< AllocationFn > allocationFn
Helper functions for allocation and 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.
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.
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.
Traversal parameters for findValueInReverseUseDefChain.
bool followUnknownOps
Specifies whether unknown/non-bufferizable/ops not included in the OpFilter of BufferizationOptions s...
bool alwaysIncludeLeaves
Specifies if leaves (that do not have further OpOperands to follow) should be returned even if they d...
bool followSameTypeOrCastsOnly
Specifies whether OpOperands with a different type that are not the result of a CastOpInterface op sh...
bool followInPlaceOnly
Specifies whether out-of-place/undecided OpOperands should be followed.
bool followEquivalentOnly
Specifies whether non-equivalent OpOperands should be followed.
bool revisitAlreadyVisitedValues
Specifies whether already visited values should be visited again.