MLIR  18.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->getDialect()->getNamespace() == dialectNamespace;
146  };
147  entries.push_back(Entry{filterFn, Entry::FilterType::ALLOW});
148  }
149 
150  /// Allow the given ops.
151  ///
152  /// This function adds one or multiple ALLOW entries.
153  template <typename... OpTys>
154  void allowOperation() {
155  (allowOperationImpl<OpTys>(), ...);
156  }
157 
158  /// Deny the given ops.
159  ///
160  /// This function adds one or multiple DENY entries.
161  template <typename... OpTys>
162  void denyOperation() {
163  (denyOperationImpl<OpTys>(), ...);
164  }
165 
166  /// Allow the given op.
167  ///
168  /// This function adds an ALLOW entry.
169  void allowOperation(StringRef opName) {
170  Entry::FilterFn filterFn = [=](Operation *op) {
171  return op->getName().getStringRef() == opName;
172  };
173  allowOperation(filterFn);
174  }
175 
176  /// Deny the given op.
177  ///
178  /// This function adds a DENY entry.
179  void denyOperation(StringRef opName) {
180  Entry::FilterFn filterFn = [=](Operation *op) {
181  return op->getName().getStringRef() == opName;
182  };
183  denyOperation(filterFn);
184  }
185 
186  /// Allow ops that are matched by `fn`.
187  ///
188  /// This function adds an ALLOW entry.
190  entries.push_back(Entry{fn, Entry::FilterType::ALLOW});
191  }
192 
193  /// Deny ops that are matched by `fn`.
194  ///
195  /// This function adds a DENY entry.
197  entries.push_back(Entry{fn, Entry::FilterType::DENY});
198  }
199 
200 private:
201  /// Return `true` if the filter has at least one ALLOW rule.
202  bool hasAllowRule() const {
203  for (const Entry &e : entries)
204  if (e.type == Entry::FilterType::ALLOW)
205  return true;
206  return false;
207  }
208 
209  /// Allow a dialect.
210  template <typename DialectT>
211  void allowDialectImpl() {
212  allowDialect(DialectT::getDialectNamespace());
213  }
214 
215  /// Deny a dialect.
216  template <typename DialectT>
217  void denyDialectImpl() {
218  denyDialect(DialectT::getDialectNamespace());
219  }
220 
221  /// Allow an op.
222  template <typename OpTy>
223  void allowOperationImpl() {
224  allowOperation(OpTy::getOperationName());
225  }
226 
227  /// Deny an op.
228  template <typename OpTy>
229  void denyOperationImpl() {
230  denyOperation(OpTy::getOperationName());
231  }
232 
233  /// A list of filter entries that determine whether an op should be allowed or
234  /// denied. If the filter has an ALLOW rule, only ops that are allowed and not
235  /// denied are allowed. If the filter does not have an ALLOW rule, only ops
236  /// that are not denied are allowed.
237  SmallVector<Entry> entries;
238 };
239 
240 /// Options for BufferizableOpInterface-based bufferization.
242  /// Allocator function: Generate a memref allocation with the given type,
243  /// dynamic extents and alignment.
244  using AllocationFn = std::function<FailureOr<Value>(
245  OpBuilder &, Location, MemRefType, ValueRange, unsigned int)>;
246  /// Deallocator function: Deallocate a buffer that was allocated with
247  /// AllocatorFn.
249  std::function<LogicalResult(OpBuilder &, Location, Value)>;
250  /// Memcpy function: Generate a memcpy between two buffers.
251  using MemCpyFn =
252  std::function<LogicalResult(OpBuilder &, Location, Value, Value)>;
253  /// Initializer function for analysis state.
254  using AnalysisStateInitFn = std::function<void(AnalysisState &)>;
255  /// Tensor -> MemRef type converter.
256  /// Parameters: Value, memory space, func op, bufferization options
258  std::function<BaseMemRefType(TensorType, Attribute memorySpace,
259  func::FuncOp, const BufferizationOptions &)>;
260  /// Tensor -> MemRef type converter.
261  /// Parameters: Value, memory space, bufferization options
262  using UnknownTypeConverterFn = std::function<BaseMemRefType(
263  Value, Attribute memorySpace, const BufferizationOptions &)>;
264 
266 
267  /// Try to cast the given op to BufferizableOpInterface if the op is allow
268  /// listed.
269  BufferizableOpInterface dynCastBufferizableOp(Operation *op) const;
270 
271  /// Try to cast the given value to BufferizableOpInterface if the op is allow
272  /// listed.
273  BufferizableOpInterface dynCastBufferizableOp(Value value) const;
274 
275  /// A filter that specifies which ops should be bufferized and which ops
276  /// should be ignored.
278 
279  /// Return `true` if the given op should be bufferized.
280  bool isOpAllowed(Operation *op) const;
281 
282  /// Helper functions for allocation, deallocation, memory copying.
283  std::optional<AllocationFn> allocationFn;
284  std::optional<DeallocationFn> deallocationFn;
285  std::optional<MemCpyFn> memCpyFn;
286 
287  /// Create a memref allocation with the given type and dynamic extents.
288  FailureOr<Value> createAlloc(OpBuilder &b, Location loc, MemRefType type,
289  ValueRange dynShape) const;
290 
291  /// Creates a memref deallocation. The given memref buffer must have been
292  /// allocated using `createAlloc`.
294  Value allocatedBuffer) const;
295 
296  /// Creates a memcpy between two given buffers.
298  Value to) const;
299 
300  /// Specifies whether not bufferizable ops are allowed in the input. If so,
301  /// bufferization.to_memref and bufferization.to_tensor ops are inserted at
302  /// the boundaries.
303  bool allowUnknownOps = false;
304 
305  /// Specifies whether function boundaries (ops in the func dialect) should be
306  /// bufferized or not.
308 
309  /// The default memory space that should be used when it cannot be inferred
310  /// from the context. If case of std::nullopt, bufferization fails when the
311  /// memory space cannot be inferred at any point.
312  std::optional<Attribute> defaultMemorySpace = Attribute();
313 
314  /// Certain ops have aliasing OpOperand/OpResult invariants (e.g., scf.for).
315  /// If this flag is set to `false`, those invariants are no longer enforced
316  /// with buffer copies.
317  ///
318  /// Note: Deactivating this flag can lead to incorrect bufferization results
319  /// when used incorrectly. This flag is useful with
320  /// `AlwaysCopyAnalysisState` which bufferizes all writing tensor
321  /// OpOperands out-of-place.
323 
324  /// This function controls buffer types on function signatures. Sets
325  /// `functionArgTypeConverterFn` and `inferFunctionResultLayout` accordingly.
326  ///
327  /// * InferLayoutMap: All function parameter types have a fully dynamic layout
328  /// map, but function result types are inferred from the body of the
329  /// function.
330  /// * FullyDynamicLayoutMap: All function parameter types and result types
331  /// have a fully dynamic layout map. This option is most efficient because
332  /// any layout map can be casted to a fully dynamic one.
333  /// * IdentityLayoutMap: All function parameter types and result types have a
334  /// static identity layout (i.e., no layout map). This option may introduce
335  /// additional buffer allocs and copies because layout maps cannot be casted
336  /// away.
337  ///
338  /// Note: Inferred layout maps may not be desireable when interacting with
339  /// external functions, because the generated function signatures will be less
340  /// predictable.
341  void setFunctionBoundaryTypeConversion(LayoutMapOption layoutMapOption);
342 
343  /// Type converter from tensors to memrefs. This type converter is used to
344  /// determine bufferized function argument types. By default, a type
345  /// converter that returns a memref type with a fully dynamic layout map is
346  /// used.
347  ///
348  /// If `bufferizeFunctionBoundaries` is not set, this function isn't used.
350 
351  /// If true, function result types are inferred from the body of the function.
352  /// Otherwise, function result type is determined by
353  /// `functionArgTypeConverterFn`.
354  ///
355  /// If `bufferizeFunctionBoundaries` is not set, this flag has no effect.
357 
358  /// Type converter from tensors to memrefs. This type converter is used if no
359  /// memref type could be inferred during bufferization. By default, a type
360  /// converter that returns a memref type with a fully dynamic layout map is
361  /// used.
363 
364  /// Seed for the analysis fuzzer. If set to `0`, the fuzzer is deactivated.
365  /// Should be used only with `testAnalysisOnly = true`.
366  unsigned analysisFuzzerSeed = 0;
367 
368  /// If set to `true`, the analysis is skipped. A buffer is copied before every
369  /// write. This flag cannot be used together with `testAnalysisOnly = true`.
370  bool copyBeforeWrite = false;
371 
372  /// If set to `true`, does not modify the IR apart from adding attributes (for
373  /// checking the results of the analysis) and post analysis steps.
374  bool testAnalysisOnly = false;
375 
376  /// If set to `true`, the IR is annotated with details about RaW conflicts.
377  /// For debugging only. Should be used together with `testAnalysisOnly`.
378  bool printConflicts = false;
379 
380  /// Buffer alignment for new memory allocations.
381  unsigned int bufferAlignment = 64;
382 
383  /// Initializer functions for analysis state. These can be used to
384  /// initialize dialect-specific analysis state.
386 };
387 
388 /// Return `true` if the given value is a BlockArgument of a func::FuncOp.
389 bool isFunctionArgument(Value value);
390 
391 /// Traversal parameters for `findValueInReverseUseDefChain`.
393  /// Specifies if leaves (that do not have further OpOperands to follow)
394  /// should be returned even if they do not match the specified filter.
395  bool alwaysIncludeLeaves = true;
396 
397  /// Specifies whether out-of-place/undecided OpOperands should be followed.
398  bool followInPlaceOnly = false;
399 
400  /// Specifies whether non-equivalent OpOperands should be followed.
401  bool followEquivalentOnly = false;
402 
403  /// Specifies whether unknown/non-bufferizable/ops not included in the
404  /// OpFilter of BufferizationOptions should be followed.
405  bool followUnknownOps = false;
406 
407  /// Specifies whether OpOperands with a different type that are not the result
408  /// of a CastOpInterface op should be followed.
410 
411  /// Specifies whether already visited values should be visited again.
412  /// (Note: This can result in infinite looping.)
414 };
415 
416 /// AnalysisState provides a variety of helper functions for dealing with
417 /// tensor values.
419 public:
420  /// Determine which OpOperand* will alias with `value` if the op is
421  /// bufferized in place. Return all tensor OpOperand* if the op is not
422  /// bufferizable.
424 
425  /// Determine which Value will alias with `opOperand` if the op is bufferized
426  /// in place. Return all tensor Values if the op is not bufferizable.
428 
429  /// Return true if `opOperand` bufferizes to a memory read. Return `true` if
430  /// the op is not bufferizable.
431  bool bufferizesToMemoryRead(OpOperand &opOperand) const;
432 
433  /// Return true if `opOperand` bufferizes to a memory write. Return true` if
434  /// the op is not bufferizable.
435  bool bufferizesToMemoryWrite(OpOperand &opOperand) const;
436 
437  /// Return true if the given `value` bufferizes to a memory write. Return
438  /// true if the value is a block argument. Return `true` if the defining op is
439  /// not bufferizable. Otherwise, consult the BufferizableOpInterface.
440  bool bufferizesToMemoryWrite(Value value) const;
441 
442  /// Return true if `opOperand` does neither read nor write but bufferizes to
443  /// an alias. Return false if the op is not bufferizable.
444  bool bufferizesToAliasOnly(OpOperand &opOperand) const;
445 
446  /// Return true if a copy can always be avoided when allocating a new tensor
447  /// for the given OpOperand.
448  bool canOmitTensorCopy(OpOperand &opOperand) const;
449 
450  /// Return true if the given value is read by an op that bufferizes to a
451  /// memory read. Also takes into account ops that create an alias but do not
452  /// read by themselves (e.g., ExtractSliceOp).
453  bool isValueRead(Value value) const;
454 
455  /// Starting from `value`, follow the use-def chain in reverse, always
456  /// selecting the aliasing OpOperands. Find and return Values for which
457  /// `condition` evaluates to true. OpOperands of such matching Values are not
458  /// traversed any further.
459  ///
460  /// When reaching the end of a chain, also return the last Value of that
461  /// chain if `config.alwaysIncludeLeaves` is set.
462  ///
463  /// Example:
464  ///
465  /// 8
466  /// |
467  /// 6* 7* +-----+----+
468  /// | | | |
469  /// 2* 3 4* 5
470  /// | | | |
471  /// +----------+----------+----------+
472  /// |
473  /// 1
474  ///
475  /// In the above example, Values with a star satisfy the condition. When
476  /// starting the traversal from Value 1, the resulting SetVector is:
477  /// { 2, 7, 8, 5 }
478  ///
479  /// Additional stopping conditions for the traversal can be specified in
480  /// `config`.
482  Value value, llvm::function_ref<bool(Value)> condition,
483  TraversalConfig config = TraversalConfig()) const;
484 
485  /// Find the values that may define the contents of the given value at
486  /// runtime. A block argument is always a definition. An OpResult is a
487  /// definition if it bufferizes to memory write. If it does not bufferize to
488  /// a memory write but has aliasing operands, we continue the lookup on these
489  /// values.
490  ///
491  /// Example: %r = tensor.insert %f into %t[%c0] : tensor<?xf32>
492  /// findDefinitions(%r) = {%r} because %r bufferizes to memory write.
493  ///
494  /// Example: %r = tensor.empty() : tensor<10xf32>
495  /// findDefinitions(%r) = {} because tensor.empty does not the define the
496  /// contents of its result (i.e., it does not bufferize to a memory write)
497  /// and it has no aliasing OpOperands.
498  ///
499  /// Example:
500  /// %a = arith.constant ... : tensor<10xf32>
501  /// %b1 = tensor.insert %f into %t : tensor<50xf32>
502  /// %b2 = tensor.extract_slice %b1[0][10][1] : tensor<50xf32> tensor<10xf32>
503  /// %r = arith.select %cond, %a, %b : tensor<10xf32>
504  /// findDefinitions(%r) = {%a, %b1}. %r and %b2 are skipped (lookup continues
505  /// in the operands) because their defining ops do not define the contents of
506  /// the tensor.
507  ///
508  /// Example:
509  /// %a = tensor.empty() : tensor<10xf32>
510  /// %b = arith.constant ... : tensor<10xf32>
511  /// %r = arith.select %cond, %a, %b : tensor<10xf32>
512  /// findDefinitions(%r) = {%b}. %a is excluded because it does not define the
513  /// contents of the tensor.
514  ///
515  /// Note: OpResults of unknown ops are handled conservatively and assumed to
516  /// be definitions.
518 
519  /// Return `true` if the given OpResult has been decided to bufferize inplace.
520  virtual bool isInPlace(OpOperand &opOperand) const;
521 
522  /// Return true if `v1` and `v2` bufferize to equivalent buffers.
523  virtual bool areEquivalentBufferizedValues(Value v1, Value v2) const;
524 
525  /// Return true if `v1` and `v2` may bufferize to aliasing buffers.
526  virtual bool areAliasingBufferizedValues(Value v1, Value v2) const;
527 
528  /// Return `true` if the given tensor has undefined contents.
529  virtual bool hasUndefinedContents(OpOperand *opOperand) const;
530 
531  /// Return true if the given tensor (or an aliasing tensor) is yielded from
532  /// the containing block. Also include all aliasing tensors in the same block.
533  ///
534  /// Note: In the absence of an analysis, an implementation may return true for
535  /// any given tensor.
536  virtual bool isTensorYielded(Value tensor) const;
537 
538  /// Return a reference to the BufferizationOptions.
539  const BufferizationOptions &getOptions() const { return options; }
540 
541  AnalysisState(const BufferizationOptions &options);
542 
543  // AnalysisState should be passed as a reference.
544  AnalysisState(const AnalysisState &) = delete;
545 
546  virtual ~AnalysisState() = default;
547 
548  static bool classof(const AnalysisState *base) { return true; }
549 
550  TypeID getType() const { return type; }
551 
552  /// Return the closest enclosing repetitive region around the given op.
554  const BufferizationOptions &options);
555 
556  /// Return the closest enclosing repetitive region around the place where the
557  /// given value is defined.
559  const BufferizationOptions &options);
560 
561  /// Return the closest enclosing repetitive region around the given block.
563  const BufferizationOptions &options);
564 
565  virtual void resetCache();
566 
567 protected:
568  AnalysisState(const BufferizationOptions &options, TypeID type);
569 
570 private:
571  /// A reference to current bufferization options.
572  const BufferizationOptions &options;
573 
574  /// The type of analysis.
575  TypeID type;
576 
577  /// Cache containing closest ancestor repetitive Region.
579  enclosingRepetitiveRegionCache;
580 };
581 
582 /// Create an AllocTensorOp for the given shaped value (memref or tensor).
583 /// If `copy` is set, the shaped value is copied. Otherwise, a tensor with
584 /// undefined contents is allocated.
587  const BufferizationOptions &options,
588  bool copy = true);
589 
590 /// Lookup the buffer for the given value. If the value was not bufferized
591 /// yet, wrap it in a ToMemrefOp. Otherwise, it is the result of a ToTensorOp,
592 /// from which the memref operand is returned.
594  const BufferizationOptions &options);
595 
596 /// Return the buffer type for a given Value (tensor) after bufferization
597 /// without bufferizing any IR.
598 ///
599 /// Note: It should be sufficient to call `getBuffer()->getType()` in most
600 /// cases. However, when a buffer type should be predicted without modifying any
601 /// IR, this function can be used.
602 ///
603 /// This function is a wrapper around BufferizableOpInterface::getBufferType.
605  const BufferizationOptions &options);
606 
607 /// Return the buffer type for a given Value (tensor) after bufferization
608 /// without bufferizing any IR. This function (and not the other overload
609 /// without `invocationStack`) can be used from `getBufferType` implementations
610 /// of the `BufferizableOpInterface`.
611 ///
612 /// Note: It should be sufficient to call `getBuffer()->getType()` in most
613 /// cases. However, when a buffer type should be predicted without modifying any
614 /// IR, this function can be used.
615 ///
616 /// This function is a wrapper around `BufferizableOpInterface::getBufferType`.
618  const BufferizationOptions &options,
619  SmallVector<Value> &invocationStack);
620 
621 /// Replace an op with replacement values. The op is deleted. Tensor OpResults
622 /// must be replaced with memref values.
624  ValueRange values);
625 
626 /// Replace an op with a new op. The new op must have the same number of
627 /// results as the replaced op. The new op may not return any tensor values.
628 template <typename OpTy, typename... Args>
630  Args &&...args) {
631  auto newOp = rewriter.create<OpTy>(op->getLoc(), std::forward<Args>(args)...);
632  replaceOpWithBufferizedValues(rewriter, op, newOp->getResults());
633  return newOp;
634 }
635 
636 /// Return a MemRefType to which the type of the given value can be bufferized.
637 ///
638 /// If possible, op bufferization implementations should not use this function
639 /// and instead infer precise memref types for tensor results by themselves.
640 ///
641 /// Unless a layout map was specified, `options.unknownTypeConverterFn`
642 /// determines what kind of layout map will be used. For best composability
643 /// (without copies), the fully dynamic layout map is used by default.
644 ///
645 /// Note: Canonicalization patterns could clean up layout maps and infer more
646 /// precise layout maps after bufferization. However, many possible
647 /// canonicalizations are currently not implemented.
648 BaseMemRefType getMemRefType(Value value, const BufferizationOptions &options,
649  MemRefLayoutAttrInterface layout = {},
650  Attribute memorySpace = nullptr);
651 
652 /// Return a MemRef type with fully dynamic layout. If the given tensor type
653 /// is unranked, return an unranked MemRef type.
654 BaseMemRefType
655 getMemRefTypeWithFullyDynamicLayout(TensorType tensorType,
656  Attribute memorySpace = nullptr);
657 
658 /// Return a MemRef type with a static identity layout (i.e., no layout map). If
659 /// the given tensor type is unranked, return an unranked MemRef type.
660 BaseMemRefType
661 getMemRefTypeWithStaticIdentityLayout(TensorType tensorType,
662  Attribute memorySpace = nullptr);
663 
664 /// Return the owner of the given value. In case of a BlockArgument that is the
665 /// owner of the block. In case of an OpResult that is the defining op.
666 Operation *getOwnerOfValue(Value value);
667 
668 /// Assuming that the given region is repetitive, find the next enclosing
669 /// repetitive region.
670 Region *getNextEnclosingRepetitiveRegion(Region *region,
671  const BufferizationOptions &options);
672 
673 /// If `region` is a parallel region, return `region`. Otherwise, find the first
674 /// enclosing parallel region of `region`. If there is no such region, return
675 /// "nullptr".
676 ///
677 /// Note: Whether a region is parallel or sequential is queried from the
678 /// `BufferizableOpInterface`.
679 Region *getParallelRegion(Region *region, const BufferizationOptions &options);
680 
681 namespace detail {
682 /// This is the default implementation of
683 /// BufferizableOpInterface::getAliasingOpOperands. Should not be called from
684 /// other places.
686  const AnalysisState &state);
687 
688 /// This is the default implementation of
689 /// BufferizableOpInterface::getBufferType. Should not be called from other
690 /// places.
693  SmallVector<Value> &invocationStack);
694 
695 /// This is the default implementation of
696 /// BufferizableOpInterface::resultBufferizesToMemoryWrite. Should not be called
697 /// from other places.
699  const AnalysisState &state);
700 
701 /// This is the default implementation of
702 /// BufferizableOpInterface::isRepetitiveRegion. Should not be called from other
703 /// places.
704 bool defaultIsRepetitiveRegion(BufferizableOpInterface bufferizableOp,
705  unsigned index);
706 
707 /// This is the default implementation of getAliasingOpOperands in case the
708 /// defining op does not implement the BufferizableOpInterface.
710 
711 /// This is the default implementation of getAliasingValues in case the owner
712 /// op does not implement the BufferizableOpInterface.
714 } // namespace detail
715 
716 } // namespace bufferization
717 } // namespace mlir
718 
720 
721 //===----------------------------------------------------------------------===//
722 // Bufferization Interfaces
723 //===----------------------------------------------------------------------===//
724 
725 #include "mlir/Dialect/Bufferization/IR/BufferizableOpInterface.h.inc"
726 
727 #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:137
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:206
Operation * create(const OperationState &state)
Creates an operation given the fields represented as an OperationState.
Definition: Builders.cpp:446
This class represents an operand of an operation.
Definition: Value.h:261
This is a value defined by a result of an operation.
Definition: Value.h:448
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:399
Tensor types represent multi-dimensional arrays, and have two variants: RankedTensorType and Unranked...
Definition: BuiltinTypes.h:90
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:372
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:93
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.
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.
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.
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...
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.
bool isFunctionArgument(Value value)
Return true if the given value is a BlockArgument of a func::FuncOp.
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.
BufferRelation
Specifies a fine-grain relationship between buffers to enable more analysis.
This header declares functions that assist transformations in the MemRef dialect.
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.
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.
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< BaseMemRefType(TensorType, Attribute memorySpace, func::FuncOp, const BufferizationOptions &)> FunctionArgTypeConverterFn
Tensor -> MemRef type converter.
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.
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.