59 #include "llvm/ADT/DenseSet.h"
60 #include "llvm/ADT/SetVector.h"
66 #define DEBUG_TYPE "one-shot-analysis"
85 "__opresult_alias_set_attr__";
95 cast<ArrayAttr>(attr).getAsValueRange<StringAttr>()));
99 if (isa<TensorType>(opOperand.
get().
getType()))
104 OpBuilder(op).getStrArrayAttr(inPlaceVector));
117 if (isa<TensorType>(v.getType()))
120 for (
Block &b : r.getBlocks())
121 for (
auto bbArg : b.getArguments())
122 if (isa<TensorType>(bbArg.getType()))
127 op->
walk([&](BufferizableOpInterface bufferizableOp) {
130 for (
OpOperand &opOperand : bufferizableOp->getOpOperands())
131 if (isa<TensorType>(opOperand.get().getType()))
132 if (bufferizableOp.mustBufferizeInPlace(opOperand, *
this))
140 auto leaderIt = equivalentInfo.findLeader(v);
141 for (
auto mit = leaderIt, meit = equivalentInfo.member_end(); mit != meit;
149 auto leaderIt = aliasInfo.findLeader(v);
150 for (
auto mit = leaderIt, meit = aliasInfo.member_end(); mit != meit; ++mit) {
157 return equivalentInfo.isEquivalent(v1, v2);
162 return aliasInfo.isEquivalent(v1, v2);
166 if (inplaceBufferized.contains(&operand))
168 inplaceBufferized.insert(&operand);
170 aliasInfo.unionSets(alias.value, operand.
get());
171 ++statNumTensorInPlace;
175 assert(!inplaceBufferized.contains(&operand) &&
176 "OpOperand was already decided to bufferize inplace");
177 ++statNumTensorOutOfPlace;
182 equivalentInfo.insert(v);
194 if (!isa<TensorType>(opResult.getType()))
200 for (
OpOperand &use : opResult.getUses())
201 undefinedTensorUses.insert(&use);
209 return undefinedTensorUses.contains(opOperand);
213 return inplaceBufferized.contains(&opOperand);
217 bool isWritten =
false;
229 if (
auto bufferizableOp =
231 return bufferizableOp.isWritable(value, *
this);
238 aliasInfo.unionSets(v1, v2);
242 equivalentInfo.unionSets(v1, v2);
255 if (!state.bufferizesToMemoryWrite(opOperand))
258 return state.isInPlace(opOperand);
280 worklist.push_back(succ);
281 while (!worklist.empty()) {
282 Block *next = worklist.pop_back_val();
283 if (llvm::is_contained(except, next))
287 if (visited.contains(next))
289 visited.insert(next);
291 worklist.push_back(succ);
375 for (
Value def : definitions) {
378 Region *rDef = state.getEnclosingRepetitiveRegion(def,
options);
389 if (nextRegion == rDef)
391 assert(nextRegion &&
"expected to find another repetitive region");
429 for (
Value def : definitions) {
430 Block *defBlock = def.getParentBlock();
431 if (
isReachable(readBlock, writeBlock, {defBlock}) &&
449 static uint64_t counter = 0;
454 std::string
id =
"C_" + std::to_string(counter++);
456 std::string conflictingWriteAttr =
462 std::string readAttr =
466 if (
auto opResult = dyn_cast<OpResult>(definition)) {
467 std::string defAttr =
468 id +
"[DEF: result " + std::to_string(opResult.getResultNumber()) +
"]";
469 opResult.getDefiningOp()->setAttr(defAttr, b.
getUnitAttr());
471 auto bbArg = cast<BlockArgument>(definition);
472 std::string defAttr =
473 id +
"[DEF: bbArg " + std::to_string(bbArg.getArgNumber()) +
"]";
474 bbArg.getOwner()->getParentOp()->setAttr(defAttr, b.
getUnitAttr());
493 .findValueInReverseUseDefChain(
494 start, [&](
Value v) {
return v == other; }, config)
501 SubsetInsertionOpInterface subsetOp) {
502 auto matchingSubset = [&](
Value val) {
503 if (
auto opResult = dyn_cast<OpResult>(val))
504 if (subsetOp.isEquivalentSubset(opResult, [&](
Value v1,
Value v2) {
505 return state.areEquivalentBufferizedValues(v1, v2);
513 state.findValueInReverseUseDefChain(value, matchingSubset);
514 return static_cast<bool>(llvm::all_of(backwardSlice, matchingSubset));
530 if (
auto subsetOp = dyn_cast<SubsetInsertionOpInterface>(readingOp)) {
538 if (uRead == &subsetOp.getDestinationOperand() &&
554 if (uRead == &subsetOp.getSourceOperand() &&
555 uConflictingWrite == &subsetOp.getDestinationOperand() &&
570 dyn_cast<SubsetInsertionOpInterface>(conflictingWritingOp))
587 if (uConflictingWrite == &subsetOp.getDestinationOperand() &&
588 state.areEquivalentBufferizedValues(
589 uRead->
get(), subsetOp.getSourceOperand().get()) &&
614 if (
options.checkParallelRegions && !usesRead.empty()) {
615 for (
OpOperand *uConflictingWrite : usesWrite) {
623 state.findValueInReverseUseDefChain(
624 uConflictingWrite->get(),
625 [&](
Value v) { return state.bufferizesToMemoryWrite(v); });
626 assert(!definitionsOrLeaves.empty() &&
627 "expected at least one definition or leaf");
631 for (
Value def : definitionsOrLeaves) {
637 <<
"\n- bufferizes out-of-place due to parallel region:\n");
638 LLVM_DEBUG(llvm::dbgs()
639 <<
" unConflictingWrite = operand "
640 << uConflictingWrite->getOperandNumber() <<
" of "
641 << *uConflictingWrite->getOwner() <<
"\n");
649 Operation *readingOp = uRead->getOwner();
650 LLVM_DEBUG(llvm::dbgs() <<
"\n- check conflict:\n");
651 LLVM_DEBUG(llvm::dbgs() <<
" uRead = operand " << uRead->getOperandNumber()
652 <<
" of " << *readingOp <<
"\n");
665 state.findDefinitionsCached(uRead->get());
666 if (definitions.empty()) {
668 LLVM_DEBUG(llvm::dbgs()
669 <<
" no conflict: read value has no definitions\n");
675 for (
OpOperand *uConflictingWrite : usesWrite) {
676 LLVM_DEBUG(llvm::dbgs() <<
" unConflictingWrite = operand "
677 << uConflictingWrite->getOperandNumber() <<
" of "
678 << *uConflictingWrite->getOwner() <<
"\n");
684 LLVM_DEBUG(llvm::dbgs() <<
"\n- useDominance = " << useDominance <<
"\n");
688 Operation *conflictingWritingOp = uConflictingWrite->getOwner();
699 if (
happensBefore(readingOp, conflictingWritingOp, domInfo)) {
700 LLVM_DEBUG(llvm::dbgs()
701 <<
" no conflict: read happens before write\n");
712 if (uConflictingWrite == uRead) {
713 LLVM_DEBUG(llvm::dbgs()
714 <<
" no conflict: read and write are same use\n");
724 LLVM_DEBUG(llvm::dbgs() <<
" no conflict: read and write are in "
725 "mutually exclusive regions\n");
732 if (conflictingWritingOp == readingOp) {
733 if (
auto bufferizableOp =
options.dynCastBufferizableOp(readingOp)) {
734 if (bufferizableOp.bufferizesToElementwiseAccess(
735 state, {uRead, uConflictingWrite})) {
737 state, uRead->get(), uConflictingWrite->get()) ||
739 state, uConflictingWrite->get(), uRead->get())) {
742 <<
" no conflict: op bufferizes to element-wise access\n");
752 LLVM_DEBUG(llvm::dbgs() <<
" no conflict: non-conflicting subsets\n");
757 if (
auto bufferizableOp =
options.dynCastBufferizableOp(readingOp)) {
758 if (bufferizableOp.isNotConflicting(uRead, uConflictingWrite, state)) {
759 LLVM_DEBUG(llvm::dbgs()
760 <<
" no conflict: op interace of reading op says 'no'\n");
765 if (conflictingWritingOp != readingOp) {
766 if (
auto bufferizableOp =
767 options.dynCastBufferizableOp(conflictingWritingOp)) {
768 if (bufferizableOp.isNotConflicting(uRead, uConflictingWrite,
772 <<
" no conflict: op interace of writing op says 'no'\n");
779 for (
Value definition : definitions) {
780 LLVM_DEBUG(llvm::dbgs() <<
" * definition = " << definition <<
"\n");
783 if (
Operation *defOp = definition.getDefiningOp()) {
786 LLVM_DEBUG(llvm::dbgs()
787 <<
" no conflict: write happens before definition\n");
791 if (defOp->isProperAncestor(conflictingWritingOp)) {
794 <<
" no conflict: write is contained in definition\n");
798 auto bbArg = cast<BlockArgument>(definition);
799 Block *block = bbArg.getOwner();
801 LLVM_DEBUG(llvm::dbgs() <<
" no conflict: definition is bbArg "
802 "and write happens outside of block\n");
813 aliases.
getAliases()[0].value == definition) {
814 LLVM_DEBUG(llvm::dbgs()
815 <<
" no conflict: definition and write are same\n");
823 LLVM_DEBUG(llvm::dbgs() <<
" => RaW CONFLICT FOUND\n");
835 state.applyOnAliases(root, [&](
Value alias) {
836 for (
auto &use : alias.
getUses())
846 state.applyOnAliases(root, [&](
Value alias) {
847 for (
auto &use : alias.
getUses()) {
849 if (state.bufferizesToMemoryRead(use)) {
869 if (!state.bufferizesToMemoryWrite(use)) {
870 AliasingValueList aliases = state.getAliasingValues(use);
871 if (llvm::any_of(aliases, [&](AliasingValue a) {
872 return state.isValueRead(a.value);
916 for (
AliasingValue alias : state.getAliasingValues(operand)) {
920 if (!checkConsistencyOnly && state.bufferizesToMemoryWrite(operand))
921 usesWrite.insert(&operand);
928 static int64_t counter = 0;
930 std::string
id =
"W_" + std::to_string(counter++);
931 if (
auto opResult = dyn_cast<OpResult>(value)) {
932 std::string attr =
id +
"[NOT-WRITABLE: result " +
933 std::to_string(opResult.getResultNumber()) +
"]";
934 opResult.getDefiningOp()->setAttr(attr, b.
getUnitAttr());
936 auto bbArg = cast<BlockArgument>(value);
937 std::string attr =
id +
"[NOT-WRITABLE: bbArg " +
938 std::to_string(bbArg.getArgNumber()) +
"]";
939 bbArg.getOwner()->getParentOp()->setAttr(attr, b.
getUnitAttr());
948 bool checkConsistencyOnly =
false) {
950 !checkConsistencyOnly && state.bufferizesToMemoryWrite(operand);
958 foundWrite = !usesWrite.empty();
965 bool foundReadOnly =
false;
966 auto checkReadOnly = [&](
Value v) {
967 if (!state.isWritable(v)) {
968 foundReadOnly =
true;
969 if (state.getOptions().printConflicts)
973 state.applyOnAliases(operand.
get(), checkReadOnly);
975 state.applyOnAliases(alias.value, checkReadOnly);
977 LLVM_DEBUG(llvm::dbgs() <<
"=> NOT WRITABLE\n");
990 OneShotAnalysisState::findDefinitionsCached(
Value value) {
991 if (!cachedDefinitions.count(value))
993 return cachedDefinitions[value];
998 cachedDefinitions.clear();
1002 static LogicalResult
1006 llvm::dbgs() <<
"//===-------------------------------------------===//\n"
1008 <<
" of " << *operand.
getOwner() <<
"\n");
1010 bool foundInterference =
1014 if (foundInterference)
1015 state.bufferizeOutOfPlace(operand);
1017 state.bufferizeInPlace(operand);
1019 LLVM_DEBUG(llvm::dbgs()
1020 <<
"//===-------------------------------------------===//\n");
1028 if (isa<TensorType>(opOperand.get().getType()))
1038 if (
auto bufferizableOp = state.getOptions().dynCastBufferizableOp(op)) {
1040 if (!isa<TensorType>(opResult.getType()))
1047 Value firstOperand = aliases.
begin()->opOperand->get();
1048 bool allEquivalent =
true;
1051 bool isInPlace = state.isInPlace(*alias.opOperand);
1052 Value operand = alias.opOperand->get();
1053 if (isEquiv && isInPlace && alias.isDefinite) {
1056 state.unionEquivalenceClasses(opResult, operand);
1057 allEquivalent =
false;
1060 if (!isEquiv || !isInPlace)
1061 allEquivalent =
false;
1062 if (!state.areEquivalentBufferizedValues(operand, firstOperand))
1063 allEquivalent =
false;
1076 if (allEquivalent && !bufferizableOp.bufferizesToAllocation(opResult))
1077 state.unionEquivalenceClasses(opResult, firstOperand);
1106 if (!traversedOps.insert(term))
1111 for (
Value v : term->getOperands()) {
1112 if (!isa<TensorType>(v.getType()))
1114 auto opResult = dyn_cast<OpResult>(v);
1117 worklist.push_back(opResult);
1119 while (!worklist.empty()) {
1120 OpResult opResult = worklist.pop_back_val();
1122 if (!traversedOps.insert(defOp))
1124 if (!term->getParentRegion()->findAncestorOpInRegion(*defOp))
1127 for (
auto alias : aliases) {
1128 Value v = alias.opOperand->get();
1129 if (!isa<TensorType>(v.
getType()))
1131 auto opResult = dyn_cast<OpResult>(v);
1134 worklist.push_back(opResult);
1143 result.push_back(op);
1162 orderedOps.push_back(op);
1164 switch (heuristic) {
1167 std::reverse(orderedOps.begin(), orderedOps.end());
1176 "expected that fuzzer seed it set");
1181 std::mt19937 g(
getOptions().analysisFuzzerSeed);
1182 llvm::shuffle(orderedOps.begin(), orderedOps.end(), g);
1186 llvm_unreachable(
"unsupported heuristic");
1202 static LogicalResult
1210 WalkResult walkResult = op->
walk([&](BufferizableOpInterface op) {
1212 if (!
options.isOpAllowed(op.getOperation()))
1216 if (!op.supportsUnstructuredControlFlow()) {
1217 for (Region &r : op->getRegions()) {
1218 if (r.getBlocks().size() > 1) {
1219 op->emitOpError(
"op or BufferizableOpInterface implementation does "
1220 "not support unstructured control flow, but at least "
1221 "one region has multiple blocks");
1222 return WalkResult::interrupt();
1229 if (walkResult.wasInterrupted())
1232 walkResult = op->
walk([&](BufferizableOpInterface op) {
1234 if (!
options.isOpAllowed(op.getOperation()))
1240 if (
auto toTensorOp = dyn_cast<ToTensorOp>(op.getOperation())) {
1241 if (!toTensorOp.getRestrict() && !toTensorOp->getUses().empty()) {
1242 op->
emitOpError(
"to_tensor ops without `restrict` are not supported by "
1243 "One-Shot Analysis");
1249 if (isa<TensorType>(opOperand.get().getType())) {
1251 opOperand, domInfo, state,
1258 op->
emitOpError(
"not bufferizable under the given constraints: "
1259 "cannot avoid RaW conflict");
1263 if (state.isInPlace(opOperand) &&
1265 opOperand, state,
true)) {
1266 op->
emitOpError(
"not bufferizable under the given constraints: would "
1267 "write to read-only buffer");
1276 return success(!walkResult.wasInterrupted());
1286 if (isa<TensorType>(opOperand.get().getType()))
1296 auto buildAliasesArray = [&](
Value v) {
1298 state.applyOnAliases(v, [&](
Value alias) {
1300 llvm::raw_string_ostream stream(buffer);
1311 if (llvm::isa<TensorType>(opResult.getType())) {
1312 opResultAliasSets.push_back(buildAliasesArray(opResult));
1315 if (!opResultAliasSets.empty())
1320 bool hasTensorBbArg =
false;
1323 for (
Block &block : r.getBlocks()) {
1326 if (llvm::isa<TensorType>(bbArg.getType())) {
1327 bbArgAliasSets.push_back(buildAliasesArray(bbArg));
1328 hasTensorBbArg =
true;
1331 blockAliasSets.push_back(b.
getArrayAttr(bbArgAliasSets));
1333 regionAliasSets.push_back(b.
getArrayAttr(blockAliasSets));
1350 if (failed(state.analyzeOp(op, domInfo)))
1358 bool failedAnalysis =
false;
1361 state.gatherUndefinedTensorUses(op);
1367 if (BufferizableOpInterface bufferizableOp =
1368 options.dynCastBufferizableOp(op))
1369 failedAnalysis |= failed(bufferizableOp.verifyAnalysis(state));
1378 return success(!failedAnalysis);
1388 "invalid combination of bufferization flags");
1390 if (
options.copyBeforeWrite) {
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 g...
static void getAliasingReads(DenseSet< OpOperand * > &res, Value root, const OneShotAnalysisState &state)
static void equivalenceAnalysis(SmallVector< Operation * > &ops, OneShotAnalysisState &state)
Analyze equivalence of tied OpResult/OpOperand pairs of the given ops.
static void setInPlaceOpOperand(OpOperand &opOperand, bool inPlace)
Mark whether OpOperand will be bufferized inplace.
static SmallVector< Operation * > bottomUpFromTerminatorsHeuristic(Operation *op, const OneShotAnalysisState &state)
"Bottom-up from terminators" heuristic.
constexpr StringLiteral kInPlaceOperandsAttrName
Attribute marker to specify op operands that bufferize in-place.
static bool isaTensor(Type t)
static void annotateNonWritableTensor(Value value)
Annotate IR with details about the detected non-writability conflict.
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 orderin...
static LogicalResult bufferizableInPlaceAnalysisImpl(OpOperand &operand, OneShotAnalysisState &state, const DominanceInfo &domInfo)
Determine if operand can be bufferized in-place.
static bool isReachable(Block *from, Block *to, ArrayRef< Block * > except)
static bool matchesInsertDestination(const AnalysisState &state, Value value, SubsetInsertionOpInterface subsetOp)
Return "true" if value is originating from a subset that is equivalent to the subset that subsetOp in...
constexpr StringLiteral kOpResultAliasSetAttrName
static bool hasEquivalentValueInReverseUseDefChain(AnalysisState &state, Value start, Value other)
Return 'true' if a tensor that is equivalent to other can be found in the reverse use-def chain of st...
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 ...
static bool canUseOpDominance(OpOperand *uRead, OpOperand *uWrite, const SetVector< Value > &definitions, AnalysisState &state)
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 void annotateOpsWithAliasSets(Operation *op, const OneShotAnalysisState &state)
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 On...
static void annotateOpsWithBufferizationMarkers(Operation *op, const OneShotAnalysisState &state)
Annotate the IR with the result of the analysis. For testing/debugging only.
static bool wouldCreateReadAfterWriteInterference(OpOperand &operand, const DominanceInfo &domInfo, OneShotAnalysisState &state, bool checkConsistencyOnly=false)
Return true if bufferizing operand inplace would create a conflict.
constexpr StringLiteral kBbArgAliasSetAttrName
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 orderin...
static void getAliasingInplaceWrites(DenseSet< OpOperand * > &res, Value root, const OneShotAnalysisState &state)
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 thei...
static void annotateConflict(OpOperand *uRead, OpOperand *uConflictingWrite, Value definition)
Annotate IR with details about the detected RaW conflict.
static bool isInplaceMemoryWrite(OpOperand &opOperand, const OneShotAnalysisState &state)
Return true if opOperand has been decided to bufferize in-place.
static llvm::ManagedStatic< PassManagerOptions > options
#define MLIR_DEFINE_EXPLICIT_TYPE_ID(CLASS_NAME)
Base class for generic analysis states.
This class provides management for the lifetime of the state used when printing the IR.
This class represents an argument of a Block.
Block represents an ordered list of Operations.
Operation * findAncestorOpInBlock(Operation &op)
Returns 'op' if 'op' lies in this block, or otherwise finds the ancestor operation of 'op' that lies ...
SuccessorRange getSuccessors()
This class is a general helper class for creating context-global objects like types,...
StringAttr getStringAttr(const Twine &bytes)
ArrayAttr getArrayAttr(ArrayRef< Attribute > value)
A class for computing basic dominance information.
bool properlyDominates(Operation *a, Operation *b, bool enclosingOpOk=true) const
Return true if operation A properly dominates operation B, i.e.
IRValueT get() const
Return the current value being used by this operand.
This class helps build Operations.
This class represents an operand of an operation.
unsigned getOperandNumber()
Return which operand this is in the OpOperand list of the Operation.
This is a value defined by a result of an operation.
Operation is the basic unit of execution within MLIR.
Attribute getAttr(StringAttr name)
Return the specified attribute if present, null otherwise.
std::enable_if_t< llvm::function_traits< std::decay_t< FnT > >::num_args==1, RetT > walk(FnT &&callback)
Walk the operation by calling the callback for each nested operation (including this one),...
MLIRContext * getContext()
Return the context this operation is associated with.
unsigned getNumOperands()
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
Block * getBlock()
Returns the operation block that contains this operation.
void setAttr(StringAttr name, Attribute value)
If the an attribute exists with the specified name, change it to the new value.
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
MutableArrayRef< OpOperand > getOpOperands()
result_type_range getResultTypes()
bool isAncestor(Operation *other)
Return true if this operation is an ancestor of the other operation.
result_range getOpResults()
Region * getParentRegion()
Returns the region to which the instruction belongs.
result_range getResults()
bool isProperAncestor(Operation *other)
Return true if this operation is a proper ancestor of the other operation.
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Operation * getParentOp()
Return the parent operation this region is attached to.
This class provides an efficient unique identifier for a specific C++ type.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
MLIRContext * getContext() const
Utility to get the associated MLIRContext that this value is defined in.
Type getType() const
Return the type of this value.
use_range getUses() const
Returns a range of all uses, which is useful for iterating over all uses.
void printAsOperand(raw_ostream &os, AsmState &state) const
Print this value as if it were an operand.
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
A utility result that is used to signal how to proceed with an ongoing walk:
static WalkResult advance()
static WalkResult interrupt()
size_t getNumAliases() const
ArrayRef< T > getAliases() const
AnalysisState provides a variety of helper functions for dealing with tensor values.
AliasingValueList getAliasingValues(OpOperand &opOperand) const
Determine which Value will alias with opOperand if the op is bufferized in place.
bool bufferizesToMemoryWrite(OpOperand &opOperand) const
Return true if opOperand bufferizes to a memory write.
SetVector< Value > findDefinitions(Value value) const
Find the values that may define the contents of the given value at runtime.
virtual void resetCache()
virtual ~Extension()
Base virtual destructor.
State for analysis-enabled bufferization.
void bufferizeOutOfPlace(OpOperand &operand)
Mark the given OpOperand as out-of-place.
bool isWritable(Value value) const
Return true if the buffer of the given tensor value is writable.
const SetVector< Value > & findDefinitionsCached(Value value)
Find the definitions of the given tensor value or retrieve them from the cache.
bool isInPlace(OpOperand &opOperand) const override
Return true if the given OpResult has been decided to bufferize inplace.
LogicalResult analyzeOp(Operation *op, const DominanceInfo &domInfo)
Analyze the given op and its nested ops.
bool isValueWritten(Value value) const
Return true if the buffer of the given tensor value is written to.
const OneShotBufferizationOptions & getOptions() const
Return a reference to the BufferizationOptions.
void unionEquivalenceClasses(Value v1, Value v2)
Union the equivalence classes of v1 and v2.
void gatherUndefinedTensorUses(Operation *op)
Find all tensor values in the given operation that have undefined contents and store them in undefine...
void resetCache() override
Reset cached data structures.
LogicalResult analyzeSingleOp(Operation *op, const DominanceInfo &domInfo)
Analyze a single op (without nested ops).
void applyOnEquivalenceClass(Value v, function_ref< void(Value)> fun) const
Apply fun to all the members of the equivalence class of v.
bool hasUndefinedContents(OpOperand *opOperand) const override
Return true if the given tensor has undefined contents.
void bufferizeInPlace(OpOperand &operand)
Mark the given OpOperand as in-place and merge the results' and operand's aliasing sets.
void applyOnAliases(Value v, function_ref< void(Value)> fun) const
Apply fun to all aliases of v.
bool areEquivalentBufferizedValues(Value v1, Value v2) const override
Return true if v1 and v2 bufferize to equivalent buffers.
OneShotAnalysisState(Operation *op, const OneShotBufferizationOptions &options)
bool areAliasingBufferizedValues(Value v1, Value v2) const override
Return true if v1 and v2 may bufferize to aliasing buffers.
void unionAliasSets(Value v1, Value v2)
Union the alias sets of v1 and v2.
void createAliasInfoEntry(Value v)
Add a new entry for v in the aliasInfo and equivalentInfo.
Operation * getOwner() const
Return the owner of this operand.
LogicalResult runOneShotBufferize(Operation *op, const OneShotBufferizationOptions &options, BufferizationStatistics *statistics=nullptr)
Run One-Shot Bufferize on the given op: Analysis + Bufferization.
LogicalResult analyzeOp(Operation *op, OneShotAnalysisState &state, BufferizationStatistics *statistics=nullptr)
Analyze op and its nested ops.
Operation * getOwnerOfValue(Value value)
Return the owner of the given value.
LogicalResult bufferizeOp(Operation *op, const BufferizationOptions &options, BufferizationStatistics *statistics=nullptr)
Bufferize op and its nested ops that implement BufferizableOpInterface.
LogicalResult insertTensorCopies(Operation *op, const OneShotBufferizationOptions &options, BufferizationStatistics *statistics=nullptr)
Resolve RaW and other conflicts by inserting bufferization.alloc_tensor ops.
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.
bool hasTensorSemantics(Operation *op)
Return "true" if the given op has tensor semantics and should be bufferized.
Include the generated interface declarations.
bool insideMutuallyExclusiveRegions(Operation *a, Operation *b)
Return true if a and b are in mutually exclusive regions as per RegionBranchOpInterface.
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
This iterator enumerates elements in "reverse" order.
A maybe aliasing OpOperand.
Options for BufferizableOpInterface-based bufferization.
BufferizableOpInterface dynCastBufferizableOp(Operation *op) const
Try to cast the given op to BufferizableOpInterface if the op is allow listed.
bool isOpAllowed(Operation *op) const
Return true if the given op should be bufferized.
Bufferization statistics for debugging.
int64_t numTensorOutOfPlace
Options for analysis-enabled bufferization.
AnalysisHeuristic analysisHeuristic
The heuristic controls the order in which ops are traversed during the analysis.
@ BottomUpFromTerminators
Traversal parameters for findValueInReverseUseDefChain.
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 followEquivalentOnly
Specifies whether non-equivalent OpOperands should be followed.