|
MLIR 22.0.0git
|
#include "mlir/Dialect/Bufferization/Transforms/OneShotAnalysis.h"#include <random>#include "mlir/Dialect/Bufferization/IR/BufferizableOpInterface.h"#include "mlir/Dialect/Bufferization/IR/Bufferization.h"#include "mlir/Dialect/Bufferization/Transforms/Bufferize.h"#include "mlir/Dialect/Bufferization/Transforms/Transforms.h"#include "mlir/Dialect/MemRef/IR/MemRef.h"#include "mlir/IR/AsmState.h"#include "mlir/IR/Dominance.h"#include "mlir/IR/Iterators.h"#include "mlir/IR/Operation.h"#include "mlir/IR/TypeUtilities.h"#include "mlir/Interfaces/ControlFlowInterfaces.h"#include "mlir/Interfaces/SubsetOpInterface.h"#include "llvm/ADT/DenseSet.h"#include "llvm/ADT/SetVector.h"#include "llvm/Support/DebugLog.h"Go to the source code of this file.
Macros | |
| #define | DEBUG_TYPE "one-shot-analysis" |
Functions | |
| static bool | isaTensor (Type t) |
| static void | setInPlaceOpOperand (OpOperand &opOperand, bool inPlace) |
| Mark whether OpOperand will be bufferized inplace. | |
| static bool | isInplaceMemoryWrite (OpOperand &opOperand, const OneShotAnalysisState &state) |
| Return true if opOperand has been decided to bufferize in-place. | |
| static bool | happensBefore (Operation *a, Operation *b, const DominanceInfo &domInfo) |
| Return true if a happens before b, i.e., a or one of its ancestors properly dominates b and b is not inside a. | |
| static bool | canUseOpDominanceDueToRegions (OpOperand *uRead, OpOperand *uWrite, const SetVector< Value > &definitions, AnalysisState &state) |
| Return true if op dominance can be used to rule out a read-after-write conflicts based on the ordering of ops. | |
| static bool | canUseOpDominanceDueToBlocks (OpOperand *uRead, OpOperand *uWrite, const SetVector< Value > &definitions, AnalysisState &state) |
| Return true if op dominance can be used to rule out a read-after-write conflicts based on the ordering of ops. | |
| static bool | canUseOpDominance (OpOperand *uRead, OpOperand *uWrite, const SetVector< Value > &definitions, AnalysisState &state) |
| static void | annotateConflict (OpOperand *uRead, OpOperand *uConflictingWrite, Value definition) |
| Annotate IR with details about the detected RaW conflict. | |
| static bool | hasEquivalentValueInReverseUseDefChain (AnalysisState &state, OpOperand *start, Value other) |
| Return 'true' if a tensor that is equivalent to other can be found in the reverse use-def chain of start. | |
| static bool | matchesInsertDestination (const AnalysisState &state, OpOperand *opOperand, SubsetInsertionOpInterface subsetOp) |
| Return "true" if the given operand's value is originating from a subset that is equivalent to the subset that subsetOp inserts into. | |
| static bool | areNonConflictingSubsets (OpOperand *uRead, OpOperand *uConflictingWrite, const AnalysisState &state) |
| Return "true" if the given "read" and potentially conflicting "write" are not conflicting due to their subset relationship. | |
| static bool | hasReadAfterWriteInterference (const DenseSet< OpOperand * > &usesRead, const DenseSet< OpOperand * > &usesWrite, const DominanceInfo &domInfo, OneShotAnalysisState &state) |
| Given sets of uses and writes, return true if there is a RaW conflict under the assumption that all given reads/writes alias the same buffer and that all given writes bufferize inplace. | |
| static void | getAliasingInplaceWrites (DenseSet< OpOperand * > &res, Value root, const OneShotAnalysisState &state) |
| static void | getAliasingReads (DenseSet< OpOperand * > &res, Value root, const OneShotAnalysisState &state) |
| static bool | wouldCreateReadAfterWriteInterference (OpOperand &operand, const DominanceInfo &domInfo, OneShotAnalysisState &state, bool checkConsistencyOnly=false) |
| Return true if bufferizing operand inplace would create a conflict. | |
| static void | annotateNonWritableTensor (Value value) |
| Annotate IR with details about the detected non-writability conflict. | |
| static bool | wouldCreateWriteToNonWritableBuffer (OpOperand &operand, OneShotAnalysisState &state, bool checkConsistencyOnly=false) |
| Return true if bufferizing operand inplace would create a write to a non-writable buffer. | |
| static LogicalResult | bufferizableInPlaceAnalysisImpl (OpOperand &operand, OneShotAnalysisState &state, const DominanceInfo &domInfo) |
| Determine if operand can be bufferized in-place. | |
| static void | equivalenceAnalysis (SmallVector< Operation * > &ops, OneShotAnalysisState &state) |
| Analyze equivalence of tied OpResult/OpOperand pairs of the given ops. | |
| static void | equivalenceAnalysis (Operation *op, OneShotAnalysisState &state) |
| Analyze equivalence of tied OpResult/OpOperand pairs of all ops contained in op. | |
| static SmallVector< Operation * > | bottomUpFromTerminatorsHeuristic (Operation *op, const OneShotAnalysisState &state) |
| "Bottom-up from terminators" heuristic. | |
| static LogicalResult | checkPreBufferizationAssumptions (Operation *op, const DominanceInfo &domInfo, OneShotAnalysisState &state) |
| Perform various checks on the input IR to see if it contains IR constructs that are unsupported by One-Shot Bufferize. | |
| static void | annotateOpsWithBufferizationMarkers (Operation *op, const OneShotAnalysisState &state) |
| Annotate the IR with the result of the analysis. For testing/debugging only. | |
| static void | annotateOpsWithAliasSets (Operation *op, const OneShotAnalysisState &state) |
Variables | |
| constexpr StringLiteral | kInPlaceOperandsAttrName = "__inplace_operands_attr__" |
| Attribute marker to specify op operands that bufferize in-place. | |
| constexpr StringLiteral | kOpResultAliasSetAttrName |
| constexpr StringLiteral | kBbArgAliasSetAttrName = "__bbarg_alias_set_attr__" |
| #define DEBUG_TYPE "one-shot-analysis" |
Definition at line 65 of file OneShotAnalysis.cpp.
Annotate IR with details about the detected RaW conflict.
Definition at line 431 of file OneShotAnalysis.cpp.
References b, mlir::Operation::getContext(), mlir::OpOperand::getOperandNumber(), mlir::detail::IROperandBase::getOwner(), and mlir::Operation::setAttr().
Referenced by hasReadAfterWriteInterference().
Annotate IR with details about the detected non-writability conflict.
Definition at line 899 of file OneShotAnalysis.cpp.
References b, and mlir::Value::getContext().
Referenced by wouldCreateWriteToNonWritableBuffer().
|
static |
Definition at line 1262 of file OneShotAnalysis.cpp.
References mlir::bufferization::OneShotAnalysisState::applyOnAliases(), b, mlir::Operation::getContext(), mlir::Operation::getOpResults(), mlir::Operation::getRegions(), kBbArgAliasSetAttrName, kOpResultAliasSetAttrName, mlir::Value::printAsOperand(), mlir::Operation::setAttr(), and mlir::Operation::walk().
Referenced by mlir::bufferization::analyzeOp().
|
static |
Annotate the IR with the result of the analysis. For testing/debugging only.
Definition at line 1252 of file OneShotAnalysis.cpp.
References mlir::Operation::getOpOperands(), mlir::bufferization::OneShotAnalysisState::isInPlace(), setInPlaceOpOperand(), and mlir::Operation::walk().
Referenced by mlir::bufferization::analyzeOp().
|
static |
Return "true" if the given "read" and potentially conflicting "write" are not conflicting due to their subset relationship.
The comments in this function are expressed in terms of tensor.extract_slice/tensor.insert_slice pairs, but apply to any subset ops that implement the SubsetInsertionOpInterface.
Definition at line 508 of file OneShotAnalysis.cpp.
References mlir::IROperand< DerivedT, IRValueT >::get(), mlir::detail::IROperandBase::getOwner(), and matchesInsertDestination().
Referenced by hasReadAfterWriteInterference().
|
static |
"Bottom-up from terminators" heuristic.
Definition at line 1071 of file OneShotAnalysis.cpp.
References mlir::Value::getDefiningOp(), mlir::Value::getType(), mlir::PostOrder, result, and mlir::Operation::walk().
Referenced by mlir::bufferization::OneShotAnalysisState::analyzeOp().
|
static |
Determine if operand can be bufferized in-place.
Definition at line 976 of file OneShotAnalysis.cpp.
References mlir::bufferization::OneShotAnalysisState::bufferizeInPlace(), mlir::bufferization::OneShotAnalysisState::bufferizeOutOfPlace(), mlir::OpOperand::getOperandNumber(), mlir::detail::IROperandBase::getOwner(), success(), wouldCreateReadAfterWriteInterference(), and wouldCreateWriteToNonWritableBuffer().
Referenced by mlir::bufferization::OneShotAnalysisState::analyzeSingleOp().
|
static |
Definition at line 423 of file OneShotAnalysis.cpp.
References canUseOpDominanceDueToBlocks(), and canUseOpDominanceDueToRegions().
Referenced by hasReadAfterWriteInterference().
|
static |
Return true if op dominance can be used to rule out a read-after-write conflicts based on the ordering of ops.
Returns false if op dominance cannot be used to due block-based loops within a region.
Refer to the canUseOpDominanceDueToRegions documentation for details on how op domiance is used during RaW conflict detection.
On a high-level, there is a potential RaW in a program if there exists a possible program execution such that there is a sequence of DEF, followed by WRITE, followed by READ. Each additional DEF resets the sequence.
Op dominance cannot be used if there is a path from block(READ) to block(WRITE) and a path from block(WRITE) to block(READ). block(DEF) should not appear on that path.
Definition at line 401 of file OneShotAnalysis.cpp.
References mlir::Operation::getBlock(), mlir::detail::IROperandBase::getOwner(), mlir::Operation::getParentRegion(), and mlir::Block::isReachable().
Referenced by canUseOpDominance().
|
static |
Return true if op dominance can be used to rule out a read-after-write conflicts based on the ordering of ops.
Returns false if op dominance cannot be used to due region-based loops.
Generalized op dominance can often be used to rule out potential conflicts due to "read happens before write". E.g., the following IR is not a RaW conflict because the read happens before the write.
Example 1: %0 = ... : tensor<?xf32> // DEF "reading_op"(%0) : tensor<?xf32> // READ %1 = "writing_op"(%0) : tensor<?xf32> -> tensor<?xf32> // WRITE
This is no longer true inside loops (or repetitive regions). In such cases, there may not be a meaningful happensBefore relationship because ops could be executed multiple times. E.g.:
Example 2: %0 = ... : tensor<?xf32> // DEF scf.for ... { "reading_op"(%0) : tensor<?xf32> // READ %1 = "writing_op"(%0) : tensor<?xf32> -> tensor<?xf32> // WRITE ... }
In the above example, reading_op happens before writing_op according to op dominance. However, both ops may happen multiple times; in particular, the second execution of reading_op happens after the first execution of writing_op. This is problematic because the tensor %0 they operate on (i.e., the "definition") is defined outside of the loop.
On a high-level, there is a potential RaW in a program if there exists a possible program execution such that there is a sequence of DEF, followed by WRITE, followed by READ. Each additional DEF resets the sequence.
E.g.: No conflict: DEF, WRITE, DEF, READ Potential conflict: DEF, READ, WRITE, READ, WRITE
Example 1 has no conflict: DEF, READ, WRITE Example 2 has a potential conflict: DEF, (READ, WRITE)* Example 3: scf.for ... { %0 = ... : tensor<?xf32> "reading_op"(%0) : tensor<?xf32> %1 = "writing_op"(%0) : tensor<?xf32> -> tensor<?xf32> ... } This has no conflict: (DEF, READ, WRITE)*
Example 4: %0 = ... : tensor<?xf32> scf.for ... { scf.for ... { "reading_op"(%0) } %1 = "writing_op"(%0) } This has a potential conflict: DEF, ((READ)*, WRITE)*
Example 5: %0 = ... : tensor<?xf32> scf.for ... { %1 = "writing_op"(%0) } scf.for ... { "reading_op"(%0) } This has a potential conflict: DEF, WRITE*, READ*
The following rules are used to rule out RaW conflicts via ordering of ops:
Definition at line 355 of file OneShotAnalysis.cpp.
References mlir::detail::IROperandBase::getOwner(), mlir::Region::getParentOp(), mlir::Operation::isAncestor(), and options.
Referenced by canUseOpDominance().
|
static |
Perform various checks on the input IR to see if it contains IR constructs that are unsupported by One-Shot Bufferize.
Definition at line 1174 of file OneShotAnalysis.cpp.
References mlir::WalkResult::advance(), mlir::Operation::emitOpError(), mlir::Operation::getOpOperands(), mlir::bufferization::OneShotAnalysisState::getOptions(), mlir::Operation::getRegions(), mlir::WalkResult::interrupt(), mlir::bufferization::OneShotAnalysisState::isInPlace(), options, success(), mlir::Operation::walk(), mlir::WalkResult::wasInterrupted(), wouldCreateReadAfterWriteInterference(), and wouldCreateWriteToNonWritableBuffer().
Referenced by mlir::bufferization::analyzeOp().
|
static |
Analyze equivalence of tied OpResult/OpOperand pairs of all ops contained in op.
Definition at line 1056 of file OneShotAnalysis.cpp.
References equivalenceAnalysis(), mlir::Operation::getResultTypes(), isaTensor(), mlir::PostOrder, and mlir::Operation::walk().
|
static |
Analyze equivalence of tied OpResult/OpOperand pairs of the given ops.
Definition at line 1006 of file OneShotAnalysis.cpp.
References mlir::bufferization::OneShotAnalysisState::areEquivalentBufferizedValues(), mlir::bufferization::OneShotAnalysisState::getOptions(), mlir::bufferization::OneShotAnalysisState::isInPlace(), and mlir::bufferization::OneShotAnalysisState::unionEquivalenceClasses().
Referenced by mlir::bufferization::OneShotAnalysisState::analyzeOp(), and equivalenceAnalysis().
|
static |
Definition at line 805 of file OneShotAnalysis.cpp.
References mlir::bufferization::OneShotAnalysisState::applyOnAliases(), mlir::Value::getUses(), and isInplaceMemoryWrite().
Referenced by wouldCreateReadAfterWriteInterference(), and wouldCreateWriteToNonWritableBuffer().
|
static |
Definition at line 816 of file OneShotAnalysis.cpp.
References mlir::bufferization::OneShotAnalysisState::applyOnAliases(), and mlir::Value::getUses().
Referenced by wouldCreateReadAfterWriteInterference().
|
static |
Return true if a happens before b, i.e., a or one of its ancestors properly dominates b and b is not inside a.
Definition at line 267 of file OneShotAnalysis.cpp.
References b, mlir::Operation::getParentOp(), mlir::Operation::isProperAncestor(), and mlir::DominanceInfo::properlyDominates().
Referenced by hasReadAfterWriteInterference().
|
static |
Return 'true' if a tensor that is equivalent to other can be found in the reverse use-def chain of start.
Note: If an OpOperand bufferizes out of place along that use-def chain, the two tensors may not materialize as equivalent buffers (but separate allocations).
Note: This function also requires that the two tensors have equivalent indexing. I.e., the tensor types do not change along the use-def chain, apart from static <-> dynamic dim casts.
Definition at line 470 of file OneShotAnalysis.cpp.
References mlir::config.
Referenced by hasReadAfterWriteInterference().
|
static |
Given sets of uses and writes, return true if there is a RaW conflict under the assumption that all given reads/writes alias the same buffer and that all given writes bufferize inplace.
A conflict is: According to SSA use-def chains, a read R is supposed to read the result of a definition W1. But because of bufferization decisions, R actually reads another definition W2.
Definition at line 590 of file OneShotAnalysis.cpp.
References annotateConflict(), areNonConflictingSubsets(), canUseOpDominance(), mlir::Block::findAncestorOpInBlock(), mlir::bufferization::OneShotAnalysisState::findDefinitionsCached(), mlir::bufferization::OneShotAnalysisState::getOptions(), happensBefore(), hasEquivalentValueInReverseUseDefChain(), and options.
Referenced by wouldCreateReadAfterWriteInterference().
Definition at line 70 of file OneShotAnalysis.cpp.
Referenced by equivalenceAnalysis(), and mlir::bufferization::func_ext::FuncOpInterface::hasTensorSemantics().
|
static |
Return true if opOperand has been decided to bufferize in-place.
Definition at line 256 of file OneShotAnalysis.cpp.
References mlir::bufferization::OneShotAnalysisState::isInPlace().
Referenced by getAliasingInplaceWrites().
|
static |
Return "true" if the given operand's value is originating from a subset that is equivalent to the subset that subsetOp inserts into.
Definition at line 485 of file OneShotAnalysis.cpp.
Referenced by areNonConflictingSubsets().
Mark whether OpOperand will be bufferized inplace.
Definition at line 89 of file OneShotAnalysis.cpp.
References mlir::IROperand< DerivedT, IRValueT >::get(), mlir::Operation::getAttr(), mlir::Operation::getNumOperands(), mlir::OpOperand::getOperandNumber(), mlir::Operation::getOpOperands(), mlir::detail::IROperandBase::getOwner(), mlir::Value::getType(), kInPlaceOperandsAttrName, and mlir::Operation::setAttr().
Referenced by annotateOpsWithBufferizationMarkers().
|
static |
Return true if bufferizing operand inplace would create a conflict.
A read R and a write W of the same alias set is a conflict if inplace bufferization of W changes the value read by R to a value different from the one that would be expected by tracing back R's origin through SSA use-def chains. A conflict can only be introduced by a new alias and/or an inplace bufferization decision.
Example: %0 = tensor.extract_slice t[...][...][1, 1] {inplace?} %1 = vector.transfer_write v1, t {inplace} : vector<5xf32>, tensor<?xf32> e = tensor.extract_slice %1 %2 = vector.transfer_write v2, %0 {inplace} : vector<6xf32>, tensor<?xf32> %3 = vector.transfer_read e, cst : tensor<?xf32>, vector<7xf32>
In the above example, the two TransferWriteOps have already been decided to bufferize inplace. Bufferizing the ExtractSliceOp inplace would create a conflict because:
If checkConsistencyOnly is true, this function checks if there is a read-after-write conflict without bufferizing operand inplace. This would indicate a problem with the current inplace bufferization decisions.
Note: If checkConsistencyOnly, this function may be called with a null OpResult. In that case, only the consistency of bufferization decisions involving aliases of the given OpOperand are checked.
Definition at line 881 of file OneShotAnalysis.cpp.
References mlir::IROperand< DerivedT, IRValueT >::get(), getAliasingInplaceWrites(), getAliasingReads(), and hasReadAfterWriteInterference().
Referenced by bufferizableInPlaceAnalysisImpl(), and checkPreBufferizationAssumptions().
|
static |
Return true if bufferizing operand inplace would create a write to a non-writable buffer.
Definition at line 918 of file OneShotAnalysis.cpp.
References annotateNonWritableTensor(), mlir::bufferization::OneShotAnalysisState::applyOnAliases(), mlir::IROperand< DerivedT, IRValueT >::get(), getAliasingInplaceWrites(), mlir::bufferization::OneShotAnalysisState::getOptions(), and mlir::bufferization::OneShotAnalysisState::isWritable().
Referenced by bufferizableInPlaceAnalysisImpl(), and checkPreBufferizationAssumptions().
|
constexpr |
Definition at line 86 of file OneShotAnalysis.cpp.
Referenced by annotateOpsWithAliasSets().
|
constexpr |
Attribute marker to specify op operands that bufferize in-place.
Definition at line 81 of file OneShotAnalysis.cpp.
Referenced by setInPlaceOpOperand().
|
constexpr |
Definition at line 83 of file OneShotAnalysis.cpp.
Referenced by annotateOpsWithAliasSets().