[mlir][bufferization][NFC] Rename getAliasingOpOperand/getAliasingOpResult
authorMatthias Springer <springerm@google.com>
Wed, 1 Feb 2023 08:33:22 +0000 (09:33 +0100)
committerMatthias Springer <springerm@google.com>
Wed, 1 Feb 2023 09:07:41 +0000 (10:07 +0100)
* `getAliasingOpOperand` => `getAliasingOpOperands`
* `getAliasingOpResult` => `getAliasingOpResults`

Also a few minor code cleanups and better documentation.

Differential Revision: https://reviews.llvm.org/D142979

15 files changed:
mlir/include/mlir/Dialect/Bufferization/IR/BufferizableOpInterface.h
mlir/include/mlir/Dialect/Bufferization/IR/BufferizableOpInterface.td
mlir/include/mlir/Dialect/Bufferization/IR/BufferizationOps.td
mlir/include/mlir/Dialect/Bufferization/IR/DstBufferizableOpInterfaceImpl.h
mlir/lib/Dialect/Arith/Transforms/BufferizableOpInterfaceImpl.cpp
mlir/lib/Dialect/Bufferization/IR/BufferizableOpInterface.cpp
mlir/lib/Dialect/Bufferization/IR/BufferizationOps.cpp
mlir/lib/Dialect/Bufferization/Transforms/FuncBufferizableOpInterfaceImpl.cpp
mlir/lib/Dialect/Bufferization/Transforms/OneShotAnalysis.cpp
mlir/lib/Dialect/Linalg/Transforms/BufferizableOpInterfaceImpl.cpp
mlir/lib/Dialect/SCF/Transforms/BufferizableOpInterfaceImpl.cpp
mlir/lib/Dialect/Shape/Transforms/BufferizableOpInterfaceImpl.cpp
mlir/lib/Dialect/SparseTensor/Transforms/BufferizableOpInterfaceImpl.cpp
mlir/lib/Dialect/Tensor/Transforms/BufferizableOpInterfaceImpl.cpp
mlir/lib/Dialect/Vector/Transforms/BufferizableOpInterfaceImpl.cpp

index 5300b13..61ead5b 100644 (file)
@@ -25,6 +25,22 @@ namespace bufferization {
 class AnalysisState;
 class BufferizableOpInterface;
 
+/// Specify fine-grain relationship between buffers to enable more analysis.
+enum class BufferRelation {
+  Unknown,
+  // TODO: ResultContainsOperand,
+  // TODO: OperandContainsResult,
+  Equivalent
+};
+
+/// A list of possible aliasing OpOperands. This list models the runtime
+/// aliasing relationship for an OpResult.
+using AliasingOpOperandList = SmallVector<OpOperand *>;
+
+/// A list of possible aliasing OpResults. This list models the runtime
+/// aliasing relationship for an OpOperand.
+using AliasingOpResultList = SmallVector<OpResult>;
+
 class OpFilter {
 public:
   /// An op filter entry. Filters can be used to specify which ops should be
@@ -300,14 +316,6 @@ struct BufferizationOptions {
   SmallVector<AnalysisStateInitFn> stateInitializers;
 };
 
-/// Specify fine-grain relationship between buffers to enable more analysis.
-enum class BufferRelation {
-  Unknown,
-  // TODO: ResultContainsOperand,
-  // TODO: OperandContainsResult,
-  Equivalent
-};
-
 /// Return `true` if the given value is a BlockArgument of a func::FuncOp.
 bool isFunctionArgument(Value value);
 
@@ -315,15 +323,15 @@ bool isFunctionArgument(Value value);
 /// tensor values.
 class AnalysisState {
 public:
-  /// Determine which OpOperand* will alias with `opResult` if the op is
+  /// Determine which OpOperand* will alias with `result` if the op is
   /// bufferized in place. Return all tensor OpOperand* if the op is not
   /// bufferizable.
-  SmallVector<OpOperand *> getAliasingOpOperand(OpResult opResult) const;
+  AliasingOpOperandList getAliasingOpOperands(OpResult result) const;
 
   /// Determine which OpResult will alias with `opOperand` if the op is
   /// bufferized in place. Return all tensor OpResults if the op is not
   /// bufferizable.
-  SmallVector<OpResult> getAliasingOpResult(OpOperand &opOperand) const;
+  AliasingOpResultList getAliasingOpResults(OpOperand &opOperand) const;
 
   /// Return true if `opOperand` bufferizes to a memory read. Return `true` if
   /// the op is not bufferizable.
@@ -567,6 +575,12 @@ Region *getEnclosingRepetitiveRegion(Block *block,
 
 namespace detail {
 /// This is the default implementation of
+/// BufferizableOpInterface::getAliasingOpOperands. Should not be called from
+/// other places.
+AliasingOpOperandList defaultGetAliasingOpOperands(OpResult opResult,
+                                                   const AnalysisState &state);
+
+/// This is the default implementation of
 /// BufferizableOpInterface::getBufferType. Should not be called from other
 /// places.
 FailureOr<BaseMemRefType>
@@ -585,13 +599,13 @@ bool defaultResultBufferizesToMemoryWrite(OpResult opResult,
 bool defaultIsRepetitiveRegion(BufferizableOpInterface bufferizableOp,
                                unsigned index);
 
-/// This is the default implementation of getAliasingOpOperand in case the
+/// This is the default implementation of getAliasingOpOperands in case the
 /// defining op does not implement the BufferizableOpInterface.
-SmallVector<OpOperand *> unknownGetAliasingOpOperand(OpResult opResult);
+AliasingOpOperandList unknownGetAliasingOpOperands(OpResult opResult);
 
-/// This is the default implementation of getAliasingOpResult in case the
-/// defining op does not implement the BufferizableOpInterface.
-SmallVector<OpResult> unknownGetAliasingOpResult(OpOperand &opOperand);
+/// This is the default implementation of getAliasingOpResults in case the
+/// owner op does not implement the BufferizableOpInterface.
+AliasingOpResultList unknownGetAliasingOpResults(OpOperand &opOperand);
 } // namespace detail
 
 } // namespace bufferization
index 95af51a..f588d91 100644 (file)
@@ -172,22 +172,52 @@ def BufferizableOpInterface : OpInterface<"BufferizableOpInterface"> {
       >,
       InterfaceMethod<
         /*desc=*/[{
-          Return the OpResult that aliases with a given OpOperand when
+          Return the OpResults that may alias with a given OpOperand when
           bufferized in-place. This method will never be called on OpOperands
           that do not have a tensor type.
 
-          Note: This method can return multiple OpResults, indicating that a
-          given OpOperand may at runtime alias with any (or multiple) of the
-          returned OpResults.
+          This method can return multiple OpResults, indicating that a given
+          OpOperand may at runtime alias with any (or multiple) of the returned
+          OpResults.
+
+          False positives are allowed in the list of OpResults, but they can
+          adversely affect the accuracy of the anlysis. On the contrary,
+          omitting potential aliases is incorrect.
+
+          One possible (conservative) implementation of this interface method,
+          that is always safe, is to return all tensor OpResults.
+
+          Examples:
+
+          ```
+          // aliasingOpResults(%t) = {%r}
+          %r = tensor.insert_slice %f into %t : tensor<10xf32>
+
+          // aliasingOpResults(%t) = {%r}
+          %r = tensor.extract_slice %t[0]][5][1]
+              : tensor<10xf32> to tensor<5xf32>
+
+          // aliasingOpResults(%t1) = {%r}
+          // aliasingOpResults(%t2) = {%r}
+          %r = arith.select %c, %t1, %t2 : tensor<10xf32>
+
+          // A hypothetical op that bufferizes to rolling a dice and based on
+          // the result to either return buffer(%t) or a newly allocated copy
+          // thereof.
+          // aliasingOpResults(%t) = {%r}
+          %r = "dummy.alias_or_copy(%t) : (tensor<10xf32>) -> (tensor<10xf32>)"
+          ```
         }],
-        /*retType=*/"::mlir::SmallVector<::mlir::OpResult>",
-        /*methodName=*/"getAliasingOpResult",
+        /*retType=*/"::mlir::bufferization::AliasingOpResultList",
+        /*methodName=*/"getAliasingOpResults",
         /*args=*/(ins "::mlir::OpOperand &":$opOperand,
                       "const ::mlir::bufferization::AnalysisState &":$state),
         /*methodBody=*/"",
         /*defaultImplementation=*/[{
           // Does not have to be implemented for ops without tensor OpOperands.
-          llvm_unreachable("getAliasingOpResult not implemented");
+          assert(opOperand.get().getType().isa<TensorType>() &&
+                 "expected OpOperand with tensor type");
+          llvm_unreachable("getAliasingOpResults not implemented");
         }]
       >,
       InterfaceMethod<
@@ -196,35 +226,51 @@ def BufferizableOpInterface : OpInterface<"BufferizableOpInterface"> {
           bufferized in-place. This method will never be called on OpResults
           that do not have a tensor type.
 
-          By default, this method is the inverse of `getAliasingOpResult`. Ops
+          By default, this method is the inverse of `getAliasingOpResults`. Ops
           with a region that yield values may want to override this method to
           return the OpOperands that are yielded by the terminator.
 
-          Note: This method can return multiple OpOperands, indicating that the
-          given OpResult may at runtime alias with any (or multiple) of the
-          returned OpOperands. This can be useful for branches and for ops such
-          as `arith.select`.
+          This method can return multiple OpOperands, indicating that a given
+          OpResult may at runtime alias with any (or multiple) of the returned
+          OpOperands.
+
+          False positives are allowed in the list of OpOperands, but they can
+          adversely affect the accuracy of the anlysis. On the contrary,
+          omitting potential aliases is incorrect.
+
+          One possible (conservative) implementation of this interface method,
+          that is always safe, is to return all tensor OpOperands.
+
+          Note: If the returned list of OpOperands is empty, this op definitely
+          bufferizes to a new allocation. In that case `bufferizesToAllocation`
+          must return `true`.
+
+          Examples:
+
+          ```
+          // aliasingOpOperands(%r) = {%t}
+          %r = tensor.insert_slice %f into %t : tensor<10xf32>
+
+          // aliasingOpOperands(%r) = {%t}
+          %r = tensor.extract_slice %t[0]][5][1]
+              : tensor<10xf32> to tensor<5xf32>
+
+          // aliasingOpOperands(%r) = {%t1, %t2}
+          %r = arith.select %c, %t1, %t2 : tensor<10xf32>
+
+          // aliasingOpOperands(%r) = {}
+          %r = te
         }],
-        /*retType=*/"::mlir::SmallVector<::mlir::OpOperand *>",
-        /*methodName=*/"getAliasingOpOperand",
+        /*retType=*/"::mlir::bufferization::AliasingOpOperandList",
+        /*methodName=*/"getAliasingOpOperands",
         /*args=*/(ins "::mlir::OpResult":$opResult,
                       "const ::mlir::bufferization::AnalysisState &":$state),
         /*methodBody=*/"",
         /*defaultImplementation=*/[{
           assert(opResult.getType().isa<TensorType>() &&
                  "expected OpResult with tensor type");
-          SmallVector<OpOperand *> result;
-          auto bufferizableOp =
-              cast<BufferizableOpInterface>($_op.getOperation());
-          for (OpOperand &opOperand : $_op.getOperation()->getOpOperands()) {
-            if (!opOperand.get().getType().isa<TensorType>())
-              continue;
-            SmallVector<OpResult> aliasingOpResults =
-                bufferizableOp.getAliasingOpResult(opOperand, state);
-            if (llvm::is_contained(aliasingOpResults, opResult))
-              result.push_back(&opOperand);
-          }
-          return result;
+          return ::mlir::bufferization::detail::defaultGetAliasingOpOperands(
+              opResult, state);
         }]
       >,
       InterfaceMethod<
@@ -285,10 +331,11 @@ def BufferizableOpInterface : OpInterface<"BufferizableOpInterface"> {
           conversion.
 
           The implementation of this method must be consistent with the
-          remaining methods, in particular `getAliasingOpOperand`. I.e., a
+          remaining methods, in particular `getAliasingOpOperands`. I.e., a
           tensor result `r` may only be replaced with:
-          a) A buffer that aliases one of buffers in getAliasingOpOperand(r).
-          b) Or: A newly allocated buffer.
+
+          a) One of the buffers in getAliasingOpOperands(r).
+          b) Or: A newly allocated buffer (only if `bufferizesToAllocation`).
 
           This method will never be called on ops that do not have at least one
           tensor operand/result.
@@ -440,7 +487,7 @@ def BufferizableOpInterface : OpInterface<"BufferizableOpInterface"> {
           cast<BufferizableOpInterface>(getOperation());
       return !bufferizableOp.bufferizesToMemoryRead(opOperand, state)
           && !bufferizableOp.bufferizesToMemoryWrite(opOperand, state)
-          && !bufferizableOp.getAliasingOpResult(opOperand, state).empty();
+          && !bufferizableOp.getAliasingOpResults(opOperand, state).empty();
     }
   }];
 }
index 909ac44..0982700 100644 (file)
@@ -100,7 +100,7 @@ def Bufferization_AllocTensorOp : Bufferization_Op<"alloc_tensor",
     bool bufferizesToMemoryWrite(OpOperand &opOperand,
                                  const AnalysisState &state);
 
-    SmallVector<OpResult> getAliasingOpResult(
+    AliasingOpResultList getAliasingOpResults(
         OpOperand &opOperand, const AnalysisState &state);
 
     FailureOr<BaseMemRefType> getBufferType(
@@ -248,7 +248,7 @@ def Bufferization_DeallocTensorOp : Bufferization_Op<"dealloc_tensor",
       return false;
     }
 
-    SmallVector<OpResult> getAliasingOpResult(
+    AliasingOpResultList getAliasingOpResults(
         OpOperand &opOperand, const AnalysisState &state) const {
       return {};
     }
@@ -409,7 +409,7 @@ def Bufferization_ToMemrefOp : Bufferization_Op<"to_memref", [
       return true;
     }
 
-    SmallVector<OpResult> getAliasingOpResult(
+    AliasingOpResultList getAliasingOpResults(
         OpOperand &opOperand, const AnalysisState &state) const {
       return {};
     }
index 4fc88eb..85a7813 100644 (file)
@@ -36,7 +36,7 @@ struct DstBufferizableOpInterfaceExternalModel
     return dstOp.isDpsInit(&opOperand);
   }
 
-  SmallVector<OpResult> getAliasingOpResult(Operation *op, OpOperand &opOperand,
+  AliasingOpResultList getAliasingOpResults(Operation *op, OpOperand &opOperand,
                                             const AnalysisState &state) const {
     // Output operands alias with their respective tied OpResults.
     auto dstOp = cast<DestinationStyleOpInterface>(op);
index 38985a3..dfea30b 100644 (file)
@@ -74,7 +74,7 @@ struct IndexCastOpInterface
     return false;
   }
 
-  SmallVector<OpResult> getAliasingOpResult(Operation *op, OpOperand &opOperand,
+  AliasingOpResultList getAliasingOpResults(Operation *op, OpOperand &opOperand,
                                             const AnalysisState &state) const {
     return {op->getResult(0)};
   }
@@ -126,14 +126,14 @@ struct SelectOpInterface
     return false;
   }
 
-  SmallVector<OpResult> getAliasingOpResult(Operation *op, OpOperand &opOperand,
+  AliasingOpResultList getAliasingOpResults(Operation *op, OpOperand &opOperand,
                                             const AnalysisState &state) const {
     return {op->getOpResult(0) /*result*/};
   }
 
-  SmallVector<OpOperand *>
-  getAliasingOpOperand(Operation *op, OpResult opResult,
-                       const AnalysisState &state) const {
+  AliasingOpOperandList
+  getAliasingOpOperands(Operation *op, OpResult opResult,
+                        const AnalysisState &state) const {
     return {&op->getOpOperand(1) /*true_value*/,
             &op->getOpOperand(2) /*false_value*/};
   }
index 16eedea..10f5e29 100644 (file)
@@ -181,8 +181,8 @@ LogicalResult BufferizableOpInterface::resolveTensorOpOperandConflicts(
     if (operandType.isa<UnrankedTensorType>())
       return op->emitError("copying of unranked tensors is not implemented");
 
-    SmallVector<OpResult> aliasingOpResults =
-        state.getAliasingOpResult(opOperand);
+    AliasingOpResultList aliasingOpResults =
+        state.getAliasingOpResults(opOperand);
     // Is the result yielded from a block? Or are deallocations turned off
     // entirely? In either case, mark the allocation as "escaping", so that it
     // will not be deallocated.
@@ -193,7 +193,7 @@ LogicalResult BufferizableOpInterface::resolveTensorOpOperandConflicts(
 
     if (aliasingOpResults.size() == 1 &&
         !state.bufferizesToMemoryWrite(opOperand) &&
-        state.getAliasingOpOperand(aliasingOpResults.front()).size() == 1 &&
+        state.getAliasingOpOperands(aliasingOpResults.front()).size() == 1 &&
         !aliasingOpResults.front().getType().isa<UnrankedTensorType>()) {
       // The op itself does not write but may create exactly one alias. Instead
       // of copying the OpOperand, copy the OpResult. The OpResult can sometimes
@@ -359,26 +359,26 @@ static void setInsertionPointAfter(OpBuilder &b, Value value) {
 /// Determine which OpOperand* will alias with `opResult` if the op is
 /// bufferized in place. Return all tensor OpOperand* if the op is not
 /// bufferizable.
-SmallVector<OpOperand *>
-AnalysisState::getAliasingOpOperand(OpResult opResult) const {
+AliasingOpOperandList
+AnalysisState::getAliasingOpOperands(OpResult opResult) const {
   if (Operation *op = opResult.getDefiningOp())
     if (auto bufferizableOp = getOptions().dynCastBufferizableOp(op))
-      return bufferizableOp.getAliasingOpOperand(opResult, *this);
+      return bufferizableOp.getAliasingOpOperands(opResult, *this);
 
   // The op is not bufferizable.
-  return detail::unknownGetAliasingOpOperand(opResult);
+  return detail::unknownGetAliasingOpOperands(opResult);
 }
 
 /// Determine which OpResult will alias with `opOperand` if the op is bufferized
 /// in place. Return all tensor OpResults if the op is not bufferizable.
-SmallVector<OpResult>
-AnalysisState::getAliasingOpResult(OpOperand &opOperand) const {
+AliasingOpResultList
+AnalysisState::getAliasingOpResults(OpOperand &opOperand) const {
   if (auto bufferizableOp =
           getOptions().dynCastBufferizableOp(opOperand.getOwner()))
-    return bufferizableOp.getAliasingOpResult(opOperand, *this);
+    return bufferizableOp.getAliasingOpResults(opOperand, *this);
 
   // The op is not bufferizable.
-  return detail::unknownGetAliasingOpResult(opOperand);
+  return detail::unknownGetAliasingOpResults(opOperand);
 }
 
 /// Return true if `opOperand` bufferizes to a memory read. Return `true` if the
@@ -440,7 +440,7 @@ bool AnalysisState::isValueRead(Value value) const {
     OpOperand *uMaybeReading = workingSet.pop_back_val();
     // Skip over all ops that neither read nor write (but create an alias).
     if (bufferizesToAliasOnly(*uMaybeReading))
-      for (OpResult opResult : getAliasingOpResult(*uMaybeReading))
+      for (OpResult opResult : getAliasingOpResults(*uMaybeReading))
         for (OpOperand &use : opResult.getUses())
           workingSet.push_back(&use);
     if (bufferizesToMemoryRead(*uMaybeReading))
@@ -470,14 +470,14 @@ llvm::SetVector<Value> AnalysisState::findValueInReverseUseDefChain(
     OpResult opResult = value.cast<OpResult>();
     BufferizableOpInterface bufferizableOp =
         options.dynCastBufferizableOp(opResult.getDefiningOp());
-    SmallVector<OpOperand *> opOperands = getAliasingOpOperand(opResult);
+    AliasingOpOperandList aliases = getAliasingOpOperands(opResult);
 
     // Stop iterating in either one of these cases:
     // * The current op is not bufferizable or excluded in the filter.
     // * There are no OpOperands to follow.
     // * There is an OpOperand, but it is not an equivalent tensor (only if
     //   `followEquivalentOnly` is set).
-    if (!bufferizableOp || opOperands.empty() ||
+    if (!bufferizableOp || aliases.empty() ||
         (followEquivalentOnly &&
          bufferizableOp.bufferRelation(opResult, *this) !=
              BufferRelation::Equivalent)) {
@@ -486,7 +486,7 @@ llvm::SetVector<Value> AnalysisState::findValueInReverseUseDefChain(
       continue;
     }
 
-    for (OpOperand *o : opOperands)
+    for (OpOperand *o : aliases)
       workingSet.insert(o->get());
   }
 
@@ -522,9 +522,9 @@ bool AnalysisState::canOmitTensorCopy(OpOperand &opOperand) const {
     return true;
 
   // Do not copy if the tensor is never read.
-  SmallVector<OpResult> aliasingOpResults = getAliasingOpResult(opOperand);
+  AliasingOpResultList aliases = getAliasingOpResults(opOperand);
   if (!bufferizesToMemoryRead(opOperand) &&
-      llvm::none_of(aliasingOpResults,
+      llvm::none_of(aliases,
                     [&](OpResult opResult) { return isValueRead(opResult); }))
     return true;
 
@@ -593,7 +593,7 @@ bool AnalysisState::isTensorYielded(Value tensor) const {
     // Note: In the absence of detailed analysis information (e.g., there may be
     // no function call analysis information), this `getAliasingOpResult` is
     // conservative and may report additional OpResults as potentially aliasing.
-    for (OpResult opResult : getAliasingOpResult(*operand))
+    for (OpResult opResult : getAliasingOpResults(*operand))
       for (OpOperand &use : opResult.getUses())
         worklist.push_back(&use);
   }
@@ -821,8 +821,8 @@ bufferization::getMemRefTypeWithStaticIdentityLayout(TensorType tensorType,
 bool bufferization::detail::defaultResultBufferizesToMemoryWrite(
     OpResult opResult, const AnalysisState &state) {
   auto bufferizableOp = cast<BufferizableOpInterface>(opResult.getDefiningOp());
-  SmallVector<OpOperand *> opOperands =
-      bufferizableOp.getAliasingOpOperand(opResult, state);
+  AliasingOpOperandList opOperands =
+      bufferizableOp.getAliasingOpOperands(opResult, state);
 
   // Case 1: OpResults that have no aliasing OpOperand usually bufferize to
   // memory writes.
@@ -882,6 +882,23 @@ bool bufferization::detail::defaultResultBufferizesToMemoryWrite(
   return false;
 }
 
+// Compute the AliasingOpOperandList for a given OpResult based on
+// getAliasingOpResults.
+AliasingOpOperandList bufferization::detail::defaultGetAliasingOpOperands(
+    OpResult opResult, const AnalysisState &state) {
+  Operation *op = opResult.getDefiningOp();
+  AliasingOpOperandList result;
+  for (OpOperand &opOperand : op->getOpOperands()) {
+    if (!opOperand.get().getType().isa<TensorType>())
+      continue;
+    AliasingOpResultList aliasingOpResults =
+        state.getAliasingOpResults(opOperand);
+    if (llvm::is_contained(aliasingOpResults, opResult))
+      result.push_back(&opOperand);
+  }
+  return result;
+}
+
 FailureOr<BaseMemRefType> bufferization::detail::defaultGetBufferType(
     Value value, const BufferizationOptions &options,
     const DenseMap<Value, BaseMemRefType> &fixedTypes) {
@@ -896,13 +913,12 @@ FailureOr<BaseMemRefType> bufferization::detail::defaultGetBufferType(
   auto opResult = value.cast<OpResult>();
   auto bufferizableOp = cast<BufferizableOpInterface>(op);
   AnalysisState state(options);
-  auto aliasingOperands = bufferizableOp.getAliasingOpOperand(opResult, state);
-  if (!aliasingOperands.empty() &&
-      bufferizableOp.bufferRelation(opResult, state) ==
-          BufferRelation::Equivalent) {
+  AliasingOpOperandList aliases = state.getAliasingOpOperands(opResult);
+  if (!aliases.empty() && bufferizableOp.bufferRelation(opResult, state) ==
+                              BufferRelation::Equivalent) {
     // If the OpResult has an equivalent OpOperand, both OpResult and
     // OpOperand bufferize to the exact same buffer type.
-    Value equivalentOperand = aliasingOperands.front()->get();
+    Value equivalentOperand = aliases.front()->get();
     return getBufferType(equivalentOperand, options, fixedTypes);
   }
 
@@ -925,20 +941,20 @@ bool bufferization::detail::defaultIsRepetitiveRegion(
   return regionInterface.isRepetitiveRegion(index);
 }
 
-SmallVector<OpOperand *>
-bufferization::detail::unknownGetAliasingOpOperand(OpResult opResult) {
+AliasingOpOperandList
+bufferization::detail::unknownGetAliasingOpOperands(OpResult opResult) {
   // Conservatively assume that everything is aliasing.
-  SmallVector<OpOperand *> r;
+  AliasingOpOperandList r;
   for (OpOperand &operand : opResult.getDefiningOp()->getOpOperands())
     if (operand.get().getType().isa<TensorType>())
       r.push_back(&operand);
   return r;
 }
 
-SmallVector<OpResult>
-bufferization::detail::unknownGetAliasingOpResult(OpOperand &opOperand) {
+AliasingOpResultList
+bufferization::detail::unknownGetAliasingOpResults(OpOperand &opOperand) {
   // Conservatively assume that everything is aliasing.
-  SmallVector<OpResult> r;
+  AliasingOpResultList r;
   for (OpResult result : opOperand.getOwner()->getOpResults())
     if (result.getType().isa<TensorType>())
       r.push_back(result);
index 61fc3aa..232e7b6 100644 (file)
@@ -226,9 +226,9 @@ bool AllocTensorOp::bufferizesToMemoryWrite(OpOperand &opOperand,
   return false;
 }
 
-SmallVector<OpResult>
-AllocTensorOp::getAliasingOpResult(OpOperand &opOperand,
-                                   const AnalysisState &state) {
+AliasingOpResultList
+AllocTensorOp::getAliasingOpResults(OpOperand &opOperand,
+                                    const AnalysisState &state) {
   // This is a new allocation. It does not alias with any other buffer.
   return {};
 }
index 896895a..ed02e2e 100644 (file)
@@ -172,21 +172,21 @@ struct CallOpInterface
         opOperand.getOperandNumber());
   }
 
-  SmallVector<OpResult> getAliasingOpResult(Operation *op, OpOperand &opOperand,
+  AliasingOpResultList getAliasingOpResults(Operation *op, OpOperand &opOperand,
                                             const AnalysisState &state) const {
     func::CallOp callOp = cast<func::CallOp>(op);
     FuncOp funcOp = getCalledFunction(callOp);
     assert(funcOp && "expected CallOp to a FuncOp");
     if (getFuncOpAnalysisState(state, funcOp) != FuncOpAnalysisState::Analyzed)
       // FuncOp not analyzed yet. Any OpResult may be aliasing.
-      return detail::unknownGetAliasingOpResult(opOperand);
+      return detail::unknownGetAliasingOpResults(opOperand);
 
     // Get aliasing results from state.
     const FuncAnalysisState &funcState = getFuncAnalysisState(state);
     auto aliasingReturnVals =
         funcState.aliasingReturnVals.lookup(funcOp).lookup(
             opOperand.getOperandNumber());
-    SmallVector<OpResult> result;
+    AliasingOpResultList result;
     for (int64_t resultIdx : aliasingReturnVals)
       result.push_back(callOp->getOpResult(resultIdx));
     return result;
@@ -209,7 +209,7 @@ struct CallOpInterface
     if (maybeEquiv) {
 #ifndef NDEBUG
       SmallVector<OpOperand *> aliasingOpOperands =
-          getAliasingOpOperand(op, opResult, state);
+          getAliasingOpOperands(op, opResult, state);
       assert(aliasingOpOperands.size() == 1 &&
              "expected exactly 1 aliasing OpOperand");
       assert(aliasingOpOperands.front()->getOperandNumber() == *maybeEquiv &&
@@ -329,7 +329,7 @@ struct ReturnOpInterface
     return false;
   }
 
-  SmallVector<OpResult> getAliasingOpResult(Operation *op, OpOperand &opOperand,
+  AliasingOpResultList getAliasingOpResults(Operation *op, OpOperand &opOperand,
                                             const AnalysisState &state) const {
     return {};
   }
index 58ff980..24a3aad 100644 (file)
@@ -147,7 +147,7 @@ void BufferizationAliasInfo::bufferizeInPlace(OpOperand &operand,
   if (inplaceBufferized.contains(&operand))
     return;
   markInPlace(operand);
-  for (OpResult result : state.getAliasingOpResult(operand))
+  for (OpResult result : state.getAliasingOpResults(operand))
     aliasInfo.unionSets(result, operand.get());
   ++statNumTensorInPlace;
 }
@@ -636,9 +636,9 @@ static bool hasReadAfterWriteInterference(
 
         // No conflict if the conflicting write and the definition are the same
         // use.
-        SmallVector<OpResult> aliasingOpResult =
-            state.getAliasingOpResult(*uConflictingWrite);
-        if (aliasingOpResult.size() == 1 && aliasingOpResult[0] == definition) {
+        AliasingOpResultList aliases =
+            state.getAliasingOpResults(*uConflictingWrite);
+        if (aliases.size() == 1 && aliases[0] == definition) {
           LLVM_DEBUG(llvm::dbgs()
                      << "    no conflict: definition and write are same\n");
           continue;
@@ -697,7 +697,7 @@ static void getAliasingReads(DenseSet<OpOperand *> &res, Value root,
       // there would then be no flow of data from the extract_slice operand to
       // its result's uses.)
       if (!state.bufferizesToMemoryWrite(use)) {
-        SmallVector<OpResult> opResults = state.getAliasingOpResult(use);
+        AliasingOpResultList opResults = state.getAliasingOpResults(use);
         if (llvm::any_of(opResults,
                          [&](OpResult r) { return state.isValueRead(r); }))
           res.insert(&use);
@@ -743,7 +743,7 @@ static bool wouldCreateReadAfterWriteInterference(
   DenseSet<OpOperand *> usesRead, usesWrite;
   getAliasingReads(usesRead, operand.get(), aliasInfo, state);
   getAliasingInplaceWrites(usesWrite, operand.get(), aliasInfo, state);
-  for (OpResult result : state.getAliasingOpResult(operand)) {
+  for (OpResult result : state.getAliasingOpResults(operand)) {
     getAliasingReads(usesRead, result, aliasInfo, state);
     getAliasingInplaceWrites(usesWrite, result, aliasInfo, state);
   }
@@ -796,8 +796,8 @@ hasPrecedingAliasingNonWritableTensor(Value value, OpOperand *currentOpOperand,
       continue;
 
     // Follow reverse SSA use-def chain.
-    SmallVector<OpOperand *> aliasingOpOperands =
-        state.getAliasingOpOperand(opResult);
+    AliasingOpOperandList aliasingOpOperands =
+        state.getAliasingOpOperands(opResult);
     for (OpOperand *opOperand : aliasingOpOperands)
       if (aliasInfo.isInPlace(*opOperand) || currentOpOperand == opOperand)
         worklist.push_back(opOperand->get());
@@ -813,7 +813,7 @@ static bool wouldCreateWriteToNonWritableBuffer(
   // Collect writes of all aliases of OpOperand and OpResult.
   DenseSet<OpOperand *> usesWrite;
   getAliasingInplaceWrites(usesWrite, operand.get(), aliasInfo, state);
-  for (OpResult result : state.getAliasingOpResult(operand)) {
+  for (OpResult result : state.getAliasingOpResults(operand)) {
     getAliasingInplaceWrites(usesWrite, result, aliasInfo, state);
   }
   if (!checkConsistencyOnly && state.bufferizesToMemoryWrite(operand))
@@ -954,7 +954,7 @@ static void equivalenceAnalysis(SmallVector<Operation *> &ops,
       for (OpResult opResult : op->getOpResults())
         if (opResult.getType().isa<TensorType>())
           for (OpOperand *opOperand :
-               bufferizableOp.getAliasingOpOperand(opResult, state))
+               bufferizableOp.getAliasingOpOperands(opResult, state))
             if (state.isInPlace(*opOperand))
               if (bufferizableOp.bufferRelation(opResult, state) ==
                   BufferRelation::Equivalent)
index f934a15..3d5f597 100644 (file)
@@ -101,9 +101,9 @@ struct LinalgOpInterface
 
   bool bufferizesToMemoryWrite(Operation *op, OpOperand &opOperand,
                                const AnalysisState &state) const {
-    // Operand is written to if it has an aliasing OpResult.
-    auto bufferizableOp = cast<BufferizableOpInterface>(op);
-    return !bufferizableOp.getAliasingOpResult(opOperand, state).empty();
+    // Operand is written to if it is not an input/init.
+    auto dpsOp = cast<DestinationStyleOpInterface>(op);
+    return dpsOp.isDpsInit(&opOperand);
   }
 
   LogicalResult bufferize(Operation *op, RewriterBase &rewriter,
index c490450..fa71a74 100644 (file)
@@ -57,7 +57,7 @@ struct ConditionOpInterface
     return false;
   }
 
-  SmallVector<OpResult> getAliasingOpResult(Operation *op, OpOperand &opOperand,
+  AliasingOpResultList getAliasingOpResults(Operation *op, OpOperand &opOperand,
                                             const AnalysisState &state) const {
     return {};
   }
@@ -104,9 +104,9 @@ struct ConditionOpInterface
 struct ExecuteRegionOpInterface
     : public BufferizableOpInterface::ExternalModel<ExecuteRegionOpInterface,
                                                     scf::ExecuteRegionOp> {
-  SmallVector<OpOperand *>
-  getAliasingOpOperand(Operation *op, OpResult opResult,
-                       const AnalysisState &state) const {
+  AliasingOpOperandList
+  getAliasingOpOperands(Operation *op, OpResult opResult,
+                        const AnalysisState &state) const {
     // ExecuteRegionOps do not have tensor OpOperands. The yielded value can be
     // any SSA value that is in scope. To allow for use-def chain traversal
     // through ExecuteRegionOps in the analysis, the corresponding yield value
@@ -164,9 +164,9 @@ struct ExecuteRegionOpInterface
 /// Bufferization of scf.if. Replace with a new scf.if that yields memrefs.
 struct IfOpInterface
     : public BufferizableOpInterface::ExternalModel<IfOpInterface, scf::IfOp> {
-  SmallVector<OpOperand *>
-  getAliasingOpOperand(Operation *op, OpResult opResult,
-                       const AnalysisState &state) const {
+  AliasingOpOperandList
+  getAliasingOpOperands(Operation *op, OpResult opResult,
+                        const AnalysisState &state) const {
     // IfOps do not have tensor OpOperands. The yielded value can be any SSA
     // value that is in scope. To allow for use-def chain traversal through
     // IfOps in the analysis, both corresponding yield values from the then/else
@@ -265,7 +265,7 @@ struct IfOpInterface
     // yield values are equivalent to each other.
     auto bufferizableOp = cast<BufferizableOpInterface>(op);
     SmallVector<OpOperand *> yieldValues =
-        bufferizableOp.getAliasingOpOperand(opResult, state);
+        bufferizableOp.getAliasingOpOperands(opResult, state);
     assert(yieldValues.size() == 2 && "expected 2 yield values");
     bool equivalentYields = state.areEquivalentBufferizedValues(
         yieldValues[0]->get(), yieldValues[1]->get());
@@ -443,7 +443,7 @@ struct ForOpInterface
     return true;
   }
 
-  SmallVector<OpResult> getAliasingOpResult(Operation *op, OpOperand &opOperand,
+  AliasingOpResultList getAliasingOpResults(Operation *op, OpOperand &opOperand,
                                             const AnalysisState &state) const {
     auto forOp = cast<scf::ForOp>(op);
     return {forOp.getResultForOpOperand(opOperand)};
@@ -657,7 +657,7 @@ struct WhileOpInterface
     return true;
   }
 
-  SmallVector<OpResult> getAliasingOpResult(Operation *op, OpOperand &opOperand,
+  AliasingOpResultList getAliasingOpResults(Operation *op, OpOperand &opOperand,
                                             const AnalysisState &state) const {
     auto whileOp = cast<scf::WhileOp>(op);
     unsigned int idx = opOperand.getOperandNumber();
@@ -952,7 +952,7 @@ struct YieldOpInterface
     return false;
   }
 
-  SmallVector<OpResult> getAliasingOpResult(Operation *op, OpOperand &opOperand,
+  AliasingOpResultList getAliasingOpResults(Operation *op, OpOperand &opOperand,
                                             const AnalysisState &state) const {
     if (isa<scf::IfOp>(op->getParentOp()))
       return {op->getParentOp()->getResult(opOperand.getOperandNumber())};
@@ -1051,7 +1051,7 @@ struct ForeachThreadOpInterface
     return true;
   }
 
-  SmallVector<OpResult> getAliasingOpResult(Operation *op, OpOperand &opOperand,
+  AliasingOpResultList getAliasingOpResults(Operation *op, OpOperand &opOperand,
                                             const AnalysisState &state) const {
     auto foreachThreadOp = cast<ForeachThreadOp>(op);
     return {foreachThreadOp.getTiedOpResult(&opOperand)};
index 8ea6075..c042f4d 100644 (file)
@@ -27,9 +27,9 @@ namespace {
 struct AssumingOpInterface
     : public BufferizableOpInterface::ExternalModel<AssumingOpInterface,
                                                     shape::AssumingOp> {
-  SmallVector<OpOperand *>
-  getAliasingOpOperand(Operation *op, OpResult opResult,
-                       const AnalysisState &state) const {
+  AliasingOpOperandList
+  getAliasingOpOperands(Operation *op, OpResult opResult,
+                        const AnalysisState &state) const {
     // AssumingOps do not have tensor OpOperands. The yielded value can be any
     // SSA value that is in scope. To allow for use-def chain traversal through
     // AssumingOps in the analysis, the corresponding yield value is considered
@@ -99,11 +99,13 @@ struct AssumingYieldOpInterface
     return false;
   }
 
-  SmallVector<OpResult> getAliasingOpResult(Operation *op, OpOperand &opOperand,
+  AliasingOpResultList getAliasingOpResults(Operation *op, OpOperand &opOperand,
                                             const AnalysisState &state) const {
     assert(isa<shape::AssumingOp>(op->getParentOp()) &&
            "expected that parent is an AssumingOp");
-    return {op->getParentOp()->getResult(opOperand.getOperandNumber())};
+    OpResult opResult =
+        op->getParentOp()->getResult(opOperand.getOperandNumber());
+    return {opResult};
   }
 
   bool mustBufferizeInPlace(Operation *op, OpOperand &opOperand,
index f7ff03e..cc3555e 100644 (file)
@@ -43,7 +43,7 @@ struct ConcatenateOpInterface
     return false;
   }
 
-  SmallVector<OpResult> getAliasingOpResult(Operation *op, OpOperand &opOperand,
+  AliasingOpResultList getAliasingOpResults(Operation *op, OpOperand &opOperand,
                                             const AnalysisState &state) const {
     return {};
   }
@@ -73,7 +73,7 @@ struct ConvertOpInterface
     return false;
   }
 
-  SmallVector<OpResult> getAliasingOpResult(Operation *op, OpOperand &opOperand,
+  AliasingOpResultList getAliasingOpResults(Operation *op, OpOperand &opOperand,
                                             const AnalysisState &state) const {
     return {};
   }
@@ -97,7 +97,7 @@ struct LoadOpInterface
     return false;
   }
 
-  SmallVector<OpResult> getAliasingOpResult(Operation *op, OpOperand &opOperand,
+  AliasingOpResultList getAliasingOpResults(Operation *op, OpOperand &opOperand,
                                             const AnalysisState &state) const {
     return {op->getOpResult(0)};
   }
@@ -136,7 +136,7 @@ struct InsertOpInterface
     return true;
   }
 
-  SmallVector<OpResult> getAliasingOpResult(Operation *op, OpOperand &opOperand,
+  AliasingOpResultList getAliasingOpResults(Operation *op, OpOperand &opOperand,
                                             const AnalysisState &state) const {
     // InsertOp returns an alias of its operand.
     assert(op->getNumResults() == 1);
@@ -164,7 +164,7 @@ struct NumberOfEntriesOpInterface
     return false;
   }
 
-  SmallVector<OpResult> getAliasingOpResult(Operation *op, OpOperand &opOperand,
+  AliasingOpResultList getAliasingOpResults(Operation *op, OpOperand &opOperand,
                                             const AnalysisState &state) const {
     return {};
   }
@@ -185,7 +185,7 @@ struct ToIndicesBufferOpInterface
     return false;
   }
 
-  SmallVector<OpResult> getAliasingOpResult(Operation *op, OpOperand &opOperand,
+  AliasingOpResultList getAliasingOpResults(Operation *op, OpOperand &opOperand,
                                             const AnalysisState &state) const {
     return {};
   }
@@ -206,7 +206,7 @@ struct ToIndicesOpInterface
     return false;
   }
 
-  SmallVector<OpResult> getAliasingOpResult(Operation *op, OpOperand &opOperand,
+  AliasingOpResultList getAliasingOpResults(Operation *op, OpOperand &opOperand,
                                             const AnalysisState &state) const {
     return {};
   }
@@ -227,7 +227,7 @@ struct ToPointersOpInterface
     return false;
   }
 
-  SmallVector<OpResult> getAliasingOpResult(Operation *op, OpOperand &opOperand,
+  AliasingOpResultList getAliasingOpResults(Operation *op, OpOperand &opOperand,
                                             const AnalysisState &state) const {
     return {};
   }
@@ -248,7 +248,7 @@ struct ToValuesOpInterface
     return false;
   }
 
-  SmallVector<OpResult> getAliasingOpResult(Operation *op, OpOperand &opOperand,
+  AliasingOpResultList getAliasingOpResults(Operation *op, OpOperand &opOperand,
                                             const AnalysisState &state) const {
     return {};
   }
index 4f44be7..9c5b7d5 100644 (file)
@@ -41,7 +41,7 @@ struct CastOpInterface
     return false;
   }
 
-  SmallVector<OpResult> getAliasingOpResult(Operation *op, OpOperand &opOperand,
+  AliasingOpResultList getAliasingOpResults(Operation *op, OpOperand &opOperand,
                                             const AnalysisState &state) const {
     return {op->getResult(0)};
   }
@@ -98,11 +98,10 @@ struct CollapseShapeOpInterface
     return false;
   }
 
-  SmallVector<OpResult> getAliasingOpResult(Operation *op, OpOperand &opOperand,
+  AliasingOpResultList getAliasingOpResults(Operation *op, OpOperand &opOperand,
                                             const AnalysisState &state) const {
-    if (&opOperand == &op->getOpOperand(0) /*src*/)
-      return {op->getOpResult(0)};
-    return {};
+    // TODO: CollapseShapeOp may allocate at runtime.
+    return {op->getOpResult(0)};
   }
 
   BufferRelation bufferRelation(Operation *op, OpResult opResult,
@@ -214,7 +213,7 @@ struct DimOpInterface
     return false;
   }
 
-  SmallVector<OpResult> getAliasingOpResult(Operation *op, OpOperand &opOperand,
+  AliasingOpResultList getAliasingOpResults(Operation *op, OpOperand &opOperand,
                                             const AnalysisState &state) const {
     return {};
   }
@@ -263,11 +262,9 @@ struct ExpandShapeOpInterface
     return false;
   }
 
-  SmallVector<OpResult> getAliasingOpResult(Operation *op, OpOperand &opOperand,
+  AliasingOpResultList getAliasingOpResults(Operation *op, OpOperand &opOperand,
                                             const AnalysisState &state) const {
-    if (&opOperand == &op->getOpOperand(0) /*src*/)
-      return {op->getOpResult(0)};
-    return {};
+    return {op->getOpResult(0)};
   }
 
   BufferRelation bufferRelation(Operation *op, OpResult opResult,
@@ -324,7 +321,7 @@ struct ExtractSliceOpInterface
     return false;
   }
 
-  SmallVector<OpResult> getAliasingOpResult(Operation *op, OpOperand &opOperand,
+  AliasingOpResultList getAliasingOpResults(Operation *op, OpOperand &opOperand,
                                             const AnalysisState &state) const {
     if (&opOperand == &op->getOpOperand(0) /*source*/)
       return {op->getOpResult(0)};
@@ -397,7 +394,7 @@ struct ExtractOpInterface
     return false;
   }
 
-  SmallVector<OpResult> getAliasingOpResult(Operation *op, OpOperand &opOperand,
+  AliasingOpResultList getAliasingOpResults(Operation *op, OpOperand &opOperand,
                                             const AnalysisState &state) const {
     return {};
   }
@@ -837,7 +834,7 @@ struct PadOpInterface
     return false;
   }
 
-  SmallVector<OpResult> getAliasingOpResult(Operation *op, OpOperand &opOperand,
+  AliasingOpResultList getAliasingOpResults(Operation *op, OpOperand &opOperand,
                                             const AnalysisState &state) const {
     return {};
   }
@@ -935,7 +932,7 @@ struct RankOpInterface
     return false;
   }
 
-  SmallVector<OpResult> getAliasingOpResult(Operation *op, OpOperand &opOperand,
+  AliasingOpResultList getAliasingOpResults(Operation *op, OpOperand &opOperand,
                                             const AnalysisState &state) const {
     return {};
   }
@@ -968,7 +965,7 @@ struct ReshapeOpInterface
     return false;
   }
 
-  SmallVector<OpResult> getAliasingOpResult(Operation *op, OpOperand &opOperand,
+  AliasingOpResultList getAliasingOpResults(Operation *op, OpOperand &opOperand,
                                             const AnalysisState &state) const {
     return {op->getOpResult(0)};
   }
@@ -1000,9 +997,9 @@ struct ReshapeOpInterface
 struct ParallelInsertSliceOpInterface
     : public BufferizableOpInterface::ExternalModel<
           ParallelInsertSliceOpInterface, ParallelInsertSliceOp> {
-  SmallVector<OpResult> getAliasingOpResult(Operation *op, OpOperand &opOperand,
+  AliasingOpResultList getAliasingOpResults(Operation *op, OpOperand &opOperand,
                                             const AnalysisState &state) const {
-      return {};
+    return {};
   }
 
   bool bufferizesToMemoryRead(Operation *op, OpOperand &opOperand,
index b095f96..a1ca0d9 100644 (file)
@@ -42,7 +42,7 @@ struct TransferReadOpInterface
     return false;
   }
 
-  SmallVector<OpResult> getAliasingOpResult(Operation *op, OpOperand &opOperand,
+  AliasingOpResultList getAliasingOpResults(Operation *op, OpOperand &opOperand,
                                             const AnalysisState &state) const {
     return {};
   }
@@ -111,7 +111,7 @@ struct GatherOpInterface
     return false;
   }
 
-  SmallVector<OpResult> getAliasingOpResult(Operation *op, OpOperand &opOperand,
+  AliasingOpResultList getAliasingOpResults(Operation *op, OpOperand &opOperand,
                                             const AnalysisState &state) const {
     return {};
   }
@@ -137,9 +137,9 @@ struct GatherOpInterface
 struct MaskOpInterface
     : public BufferizableOpInterface::ExternalModel<MaskOpInterface,
                                                     vector::MaskOp> {
-  SmallVector<OpOperand *>
-  getAliasingOpOperand(Operation *op, OpResult opResult,
-                       const AnalysisState &state) const {
+  AliasingOpOperandList
+  getAliasingOpOperands(Operation *op, OpResult opResult,
+                        const AnalysisState &state) const {
     // MaskOps do not have tensor OpOperands. The yielded values are the result
     // of the wrapped op.
     auto maskOp = cast<vector::MaskOp>(op);
@@ -239,7 +239,7 @@ struct YieldOpInterface
     return false;
   }
 
-  SmallVector<OpResult> getAliasingOpResult(Operation *op, OpOperand &opOperand,
+  AliasingOpResultList getAliasingOpResults(Operation *op, OpOperand &opOperand,
                                             const AnalysisState &state) const {
     return {op->getParentOp()->getResult(opOperand.getOperandNumber())};
   }