57#include "llvm/ADT/DenseSet.h"
58#include "llvm/ADT/SetVector.h"
59#include "llvm/Support/DebugLog.h"
65#define DEBUG_TYPE "one-shot-analysis"
84 "__opresult_alias_set_attr__";
94 cast<ArrayAttr>(attr).getAsValueRange<StringAttr>()));
103 if (isa<TensorLikeType>(opOperand.
get().
getType()))
108 OpBuilder(op).getStrArrayAttr(inPlaceVector));
121 if (isa<TensorLikeType>(v.getType()))
124 for (
Block &
b : r.getBlocks())
125 for (
auto bbArg :
b.getArguments())
126 if (isa<TensorLikeType>(bbArg.getType()))
131 op->
walk([&](BufferizableOpInterface bufferizableOp) {
132 if (!
options.isOpAllowed(bufferizableOp))
134 for (
OpOperand &opOperand : bufferizableOp->getOpOperands())
135 if (isa<TensorLikeType>(opOperand.get().getType()))
136 if (bufferizableOp.mustBufferizeInPlace(opOperand, *
this))
144 auto leaderIt = equivalentInfo.findLeader(v);
145 for (
auto mit = leaderIt, meit = equivalentInfo.member_end(); mit != meit;
153 auto leaderIt = aliasInfo.findLeader(v);
154 for (
auto mit = leaderIt, meit = aliasInfo.member_end(); mit != meit; ++mit) {
161 return equivalentInfo.isEquivalent(v1, v2);
166 return aliasInfo.isEquivalent(v1, v2);
170 if (inplaceBufferized.contains(&operand))
172 inplaceBufferized.insert(&operand);
173 for (AliasingValue alias : getAliasingValues(operand))
174 aliasInfo.unionSets(alias.value, operand.
get());
175 ++statNumTensorInPlace;
179 assert(!inplaceBufferized.contains(&operand) &&
180 "OpOperand was already decided to bufferize inplace");
181 ++statNumTensorOutOfPlace;
186 equivalentInfo.insert(v);
192 auto bufferizableOp =
getOptions().dynCastBufferizableOp(op);
198 if (!isa<TensorLikeType>(opResult.getType()))
203 if (opResult.getUses().empty())
207 OpOperand *opOperand = &(*opResult.getUses().begin());
209 for (
OpOperand &use : opResult.getUses())
210 undefinedTensorUses.insert(&use);
218 return undefinedTensorUses.contains(opOperand);
222 return inplaceBufferized.contains(&opOperand);
226 bool isWritten =
false;
229 if (
isInPlace(use) && bufferizesToMemoryWrite(use))
238 if (
auto bufferizableOp =
240 return bufferizableOp.isWritable(value, *
this);
247 aliasInfo.unionSets(v1, v2);
251 equivalentInfo.unionSets(v1, v2);
264 if (!state.bufferizesToMemoryWrite(opOperand))
364 for (
Value def : definitions) {
367 Region *rDef = state.getEnclosingRepetitiveRegion(def,
options);
377 Region *nextRegion = getNextEnclosingRepetitiveRegion(rRead,
options);
378 if (nextRegion == rDef)
380 assert(nextRegion &&
"expected to find another repetitive region");
418 for (
Value def : definitions) {
419 Block *defBlock = def.getParentBlock();
420 if (readBlock->
isReachable(writeBlock, {defBlock}) &&
438 static uint64_t counter = 0;
443 std::string
id =
"C_" + std::to_string(counter++);
445 std::string conflictingWriteAttr =
452 std::string readAttr =
456 if (
auto opResult = dyn_cast<OpResult>(definition)) {
457 std::string defAttr =
458 id +
"[DEF: result " + std::to_string(opResult.getResultNumber()) +
"]";
459 opResult.getDefiningOp()->setDiscardableAttr(defAttr,
b.getUnitAttr());
461 auto bbArg = cast<BlockArgument>(definition);
462 std::string defAttr =
463 id +
"[DEF: bbArg " + std::to_string(bbArg.getArgNumber()) +
"]";
464 bbArg.getOwner()->getParentOp()->setDiscardableAttr(defAttr,
480 TraversalConfig config;
481 config.followEquivalentOnly =
true;
482 config.alwaysIncludeLeaves =
false;
483 config.followSameTypeOrCastsOnly =
true;
485 .findValueInReverseUseDefChain(
486 start, [&](
Value v) {
return v == other; }, config)
494 SubsetInsertionOpInterface subsetOp) {
495 auto matchingSubset = [&](
Value val) {
496 if (
auto opResult = dyn_cast<OpResult>(val))
497 if (subsetOp.isEquivalentSubset(opResult, [&](
Value v1,
Value v2) {
498 return state.areEquivalentBufferizedValues(v1, v2);
506 state.findValueInReverseUseDefChain(opOperand, matchingSubset);
507 return llvm::all_of(backwardSlice, matchingSubset);
523 if (
auto subsetOp = dyn_cast<SubsetInsertionOpInterface>(readingOp)) {
531 if (uRead == &subsetOp.getDestinationOperand() &&
547 if (uRead == &subsetOp.getSourceOperand() &&
548 uConflictingWrite == &subsetOp.getDestinationOperand() &&
563 dyn_cast<SubsetInsertionOpInterface>(conflictingWritingOp))
580 if (uConflictingWrite == &subsetOp.getDestinationOperand() &&
581 state.areEquivalentBufferizedValues(
582 uRead->
get(), subsetOp.getSourceOperand().get()) &&
606 if (
options.checkParallelRegions && !usesRead.empty()) {
607 for (
OpOperand *uConflictingWrite : usesWrite) {
615 state.findValueInReverseUseDefChain(uConflictingWrite, [&](
Value v) {
616 return state.bufferizesToMemoryWrite(v);
618 assert(!definitionsOrLeaves.empty() &&
619 "expected at least one definition or leaf");
623 for (
Value def : definitionsOrLeaves) {
624 if (getParallelRegion(def.getParentRegion(),
options) !=
625 getParallelRegion(uConflictingWrite->getOwner()->getParentRegion(),
627 LDBG() <<
"\n- bufferizes out-of-place due to parallel region:\n"
628 <<
" unConflictingWrite = operand "
629 << uConflictingWrite->getOperandNumber() <<
" of "
639 Operation *readingOp = uRead->getOwner();
640 LDBG() <<
"\n- check conflict:\n"
641 <<
" uRead = operand " << uRead->getOperandNumber() <<
" of "
655 if (definitions.empty()) {
657 LDBG() <<
" no conflict: read value has no definitions";
663 for (
OpOperand *uConflictingWrite : usesWrite) {
664 LDBG() <<
" unConflictingWrite = operand "
665 << uConflictingWrite->getOperandNumber() <<
" of "
673 LDBG() <<
"\n- useDominance = " << useDominance;
677 Operation *conflictingWritingOp = uConflictingWrite->getOwner();
688 if (
happensBefore(readingOp, conflictingWritingOp, domInfo)) {
689 LDBG() <<
" no conflict: read happens before write";
700 if (uConflictingWrite == uRead) {
701 LDBG() <<
" no conflict: read and write are same use";
710 if (state.insideMutuallyExclusiveRegions(readingOp,
711 conflictingWritingOp)) {
712 LDBG() <<
" no conflict: read and write are in "
713 "mutually exclusive regions";
720 if (conflictingWritingOp == readingOp) {
721 if (
auto bufferizableOp =
options.dynCastBufferizableOp(readingOp)) {
722 if (bufferizableOp.bufferizesToElementwiseAccess(
723 state, {uRead, uConflictingWrite})) {
725 state, uRead, uConflictingWrite->get()) ||
727 state, uConflictingWrite, uRead->get())) {
728 LDBG() <<
" no conflict: op bufferizes to element-wise access";
738 LDBG() <<
" no conflict: non-conflicting subsets";
743 if (
auto bufferizableOp =
options.dynCastBufferizableOp(readingOp)) {
744 if (bufferizableOp.isNotConflicting(uRead, uConflictingWrite, state)) {
745 LDBG() <<
" no conflict: op interace of reading op says 'no'";
750 if (conflictingWritingOp != readingOp) {
751 if (
auto bufferizableOp =
752 options.dynCastBufferizableOp(conflictingWritingOp)) {
753 if (bufferizableOp.isNotConflicting(uRead, uConflictingWrite,
755 LDBG() <<
" no conflict: op interace of writing op says 'no'";
762 for (
Value definition : definitions) {
763 LDBG() <<
" * definition = " << definition;
766 if (
Operation *defOp = definition.getDefiningOp()) {
769 LDBG() <<
" no conflict: write happens before definition";
773 if (defOp->isProperAncestor(conflictingWritingOp)) {
774 LDBG() <<
" no conflict: write is contained in definition";
778 auto bbArg = cast<BlockArgument>(definition);
779 Block *block = bbArg.getOwner();
781 LDBG() <<
" no conflict: definition is bbArg "
782 "and write happens outside of block";
791 AliasingValueList aliases = state.getAliasingValues(*uConflictingWrite);
792 if (aliases.getNumAliases() == 1 &&
793 aliases.getAliases()[0].value == definition) {
794 LDBG() <<
" no conflict: definition and write are same";
802 LDBG() <<
" => RaW CONFLICT FOUND";
815 for (
auto &use : alias.
getUses())
826 for (
auto &use : alias.
getUses()) {
828 if (state.bufferizesToMemoryRead(use)) {
848 if (!state.bufferizesToMemoryWrite(use)) {
849 AliasingValueList aliases = state.getAliasingValues(use);
850 if (llvm::any_of(aliases, [&](AliasingValue a) {
851 return state.isValueRead(a.value);
895 for (AliasingValue alias : state.getAliasingValues(operand)) {
899 if (!checkConsistencyOnly && state.bufferizesToMemoryWrite(operand))
900 usesWrite.insert(&operand);
909 std::string
id =
"W_" + std::to_string(counter++);
910 if (
auto opResult = dyn_cast<OpResult>(value)) {
911 std::string attr =
id +
"[NOT-WRITABLE: result " +
912 std::to_string(opResult.getResultNumber()) +
"]";
913 opResult.getDefiningOp()->setDiscardableAttr(attr,
b.getUnitAttr());
915 auto bbArg = cast<BlockArgument>(value);
916 std::string attr =
id +
"[NOT-WRITABLE: bbArg " +
917 std::to_string(bbArg.getArgNumber()) +
"]";
918 bbArg.getOwner()->getParentOp()->setDiscardableAttr(attr,
b.getUnitAttr());
927 bool checkConsistencyOnly =
false) {
929 !checkConsistencyOnly && state.bufferizesToMemoryWrite(operand);
935 for (AliasingValue alias : state.getAliasingValues(operand))
937 foundWrite = !usesWrite.empty();
944 bool foundReadOnly =
false;
945 auto checkReadOnly = [&](
Value v) {
947 foundReadOnly =
true;
953 for (AliasingValue alias : state.getAliasingValues(operand))
956 LDBG() <<
"=> NOT WRITABLE";
968const llvm::SetVector<Value> &
971 if (!cachedDefinitions.count(value))
972 cachedDefinitions[value] = findDefinitions(opOperand);
973 return cachedDefinitions[value];
978 auto key = std::make_pair(uRead, uConflictingWrite);
979 auto [it,
inserted] = nonConflictingSubsetCache.try_emplace(key,
false);
986 AnalysisState::resetCache();
987 cachedDefinitions.clear();
988 nonConflictingSubsetCache.clear();
995 LDBG() <<
"//===-------------------------------------------===//\n"
999 bool foundInterference =
1003 if (foundInterference)
1008 LDBG() <<
"//===-------------------------------------------===//";
1016 if (isa<TensorLikeType>(opOperand.get().getType()))
1026 if (
auto bufferizableOp = state.
getOptions().dynCastBufferizableOp(op)) {
1027 for (
OpResult opResult : op->getOpResults()) {
1028 if (!isa<TensorLikeType>(opResult.getType()))
1030 AliasingOpOperandList aliases = state.getAliasingOpOperands(opResult);
1031 if (aliases.getNumAliases() == 0)
1035 Value firstOperand = aliases.begin()->opOperand->get();
1036 bool allEquivalent =
true;
1037 for (AliasingOpOperand alias : aliases) {
1038 bool isEquiv = alias.relation == BufferRelation::Equivalent;
1039 bool isInPlace = state.
isInPlace(*alias.opOperand);
1040 Value operand = alias.opOperand->get();
1041 if (isEquiv && isInPlace && alias.isDefinite) {
1045 allEquivalent =
false;
1048 if (!isEquiv || !isInPlace)
1049 allEquivalent =
false;
1051 allEquivalent =
false;
1064 if (allEquivalent && !bufferizableOp.bufferizesToAllocation(opResult))
1087static SmallVector<Operation *>
1094 if (!traversedOps.insert(term))
1099 for (
Value v : term->getOperands()) {
1100 if (!isa<TensorLikeType>(v.
getType()))
1102 auto opResult = dyn_cast<OpResult>(v);
1105 worklist.push_back(opResult);
1107 while (!worklist.empty()) {
1108 OpResult opResult = worklist.pop_back_val();
1110 if (!traversedOps.insert(defOp))
1112 if (!term->getParentRegion()->findAncestorOpInRegion(*defOp))
1114 AliasingOpOperandList aliases = state.getAliasingOpOperands(opResult);
1115 for (
auto alias : aliases) {
1116 Value v = alias.opOperand->get();
1117 if (!isa<TensorLikeType>(v.
getType()))
1119 auto opResult = dyn_cast<OpResult>(v);
1122 worklist.push_back(opResult);
1130 if (!traversedOps.contains(op) && hasTensorSemantics(op))
1148 if (!hasTensorSemantics(op))
1150 orderedOps.push_back(op);
1152 switch (heuristic) {
1155 std::reverse(orderedOps.begin(), orderedOps.end());
1164 "expected that fuzzer seed it set");
1169 std::mt19937 g(
getOptions().analysisFuzzerSeed);
1170 llvm::shuffle(orderedOps.begin(), orderedOps.end(), g);
1174 llvm_unreachable(
"unsupported heuristic");
1198 WalkResult walkResult = op->
walk([&](BufferizableOpInterface op) {
1200 if (!
options.isOpAllowed(op.getOperation()))
1204 if (!op.supportsUnstructuredControlFlow()) {
1206 if (r.getBlocks().size() > 1) {
1207 op->
emitOpError(
"op or BufferizableOpInterface implementation does "
1208 "not support unstructured control flow, but at least "
1209 "one region has multiple blocks");
1220 walkResult = op->
walk([&](BufferizableOpInterface op) {
1222 if (!
options.isOpAllowed(op.getOperation()))
1228 if (
auto toTensorOp = dyn_cast<ToTensorOp>(op.getOperation())) {
1229 if (!toTensorOp.getRestrict() && !toTensorOp->getUses().empty()) {
1230 op->
emitOpError(
"to_tensor ops without `restrict` are not supported by "
1231 "One-Shot Analysis");
1237 if (isa<TensorLikeType>(opOperand.get().getType())) {
1239 opOperand, domInfo, state,
1246 op->
emitOpError(
"not bufferizable under the given constraints: "
1247 "cannot avoid RaW conflict");
1253 opOperand, state,
true)) {
1254 op->
emitOpError(
"not bufferizable under the given constraints: would "
1255 "write to read-only buffer");
1274 if (isa<TensorLikeType>(opOperand.get().getType()))
1284 auto buildAliasesArray = [&](
Value v) {
1288 llvm::raw_string_ostream stream(buffer);
1290 aliases.push_back(
b.getStringAttr(buffer));
1292 return b.getArrayAttr(aliases);
1299 if (llvm::isa<TensorLikeType>(opResult.getType())) {
1300 opResultAliasSets.push_back(buildAliasesArray(opResult));
1303 if (!opResultAliasSets.empty())
1305 b.getArrayAttr(opResultAliasSets));
1309 bool hasTensorBbArg =
false;
1312 for (
Block &block : r.getBlocks()) {
1315 if (llvm::isa<TensorLikeType>(bbArg.getType())) {
1316 bbArgAliasSets.push_back(buildAliasesArray(bbArg));
1317 hasTensorBbArg =
true;
1320 blockAliasSets.push_back(
b.getArrayAttr(bbArgAliasSets));
1322 regionAliasSets.push_back(
b.getArrayAttr(blockAliasSets));
1326 b.getArrayAttr(regionAliasSets));
1340 if (failed(state.
analyzeOp(op, domInfo)))
1348 bool failedAnalysis =
false;
1357 if (BufferizableOpInterface bufferizableOp =
1358 options.dynCastBufferizableOp(op))
1359 failedAnalysis |= failed(bufferizableOp.verifyAnalysis(state));
1368 return success(!failedAnalysis);
1377 "invalid combination of bufferization flags");
1379 if (
options.copyBeforeWrite) {
*if copies could not be generated due to yet unimplemented cases *copyInPlacementStart and copyOutPlacementStart in copyPlacementBlock *specify the insertion points where the incoming copies and outgoing should be inserted(the insertion happens right before the *insertion point). Since `begin` can itself be invalidated due to the memref *rewriting done from this method
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.
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 SmallVector< Operation * > bottomUpFromTerminatorsHeuristic(Operation *op, const OneShotAnalysisState &state)
"Bottom-up from terminators" heuristic.
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.
constexpr StringLiteral kOpResultAliasSetAttrName
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 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 sub...
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 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 st...
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)
static Operation * getOwnerOfValue(Value value)
Base class for generic analysis states.
AnalysisState(LatticeAnchor anchor)
Create the analysis state on the given lattice anchor.
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 ...
bool isReachable(Block *other, SmallPtrSet< Block *, 16 > &&except={})
Return "true" if there is a path from this block to the given block (according to the successors rela...
This class is a general helper class for creating context-global objects like types,...
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() const
Return which operand this is in the OpOperand list of the Operation.
Set of flags used to control the behavior of the various IR print methods (e.g.
This is a value defined by a result of an operation.
A wrapper class that allows for printing an operation with a set of flags, useful to act as a "stream...
Operation is the basic unit of execution within MLIR.
Attribute getDiscardableAttr(StringRef name)
Access a discardable attribute by name, returns a null Attribute if the discardable attribute does no...
Block * getBlock()
Returns the operation block that contains this operation.
void setDiscardableAttr(StringAttr name, Attribute value)
Set a discardable attribute by name.
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
MutableArrayRef< OpOperand > getOpOperands()
unsigned getNumOperands()
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
result_type_range getResultTypes()
bool isAncestor(Operation *other)
Return true if this operation is an ancestor of the other operation.
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),...
result_range getOpResults()
result_range getResults()
Region * getParentRegion()
Returns the region to which the instruction belongs.
bool isProperAncestor(Operation *other)
Return true if this operation is a proper ancestor of the other operation.
MLIRContext * getContext()
Return the context this operation is associated with.
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()
bool wasInterrupted() const
Returns true if the walk was interrupted.
static WalkResult interrupt()
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(OpOperand *opOperand)
Find the definitions of the given operand's 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.
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.
const OneShotBufferizationOptions & getOptions() const
Return a reference to the BufferizationOptions.
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.
int64_t getStatNumTensorOutOfPlace() const
bool hasUndefinedContents(OpOperand *opOperand) const override
Return true if the given tensor has undefined contents.
bool areNonConflictingSubsetsCached(OpOperand *uRead, OpOperand *uConflictingWrite)
Return whether uRead and uConflictingWrite are non-conflicting subsets, with caching.
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.
int64_t getStatNumTensorInPlace() const
Operation * getOwner() const
Return the owner of this operand.
LogicalResult bufferizeOp(Operation *op, const BufferizationOptions &options, BufferizationState &bufferizationState, BufferizationStatistics *statistics=nullptr)
Bufferize op and its nested ops that implement BufferizableOpInterface.
LogicalResult analyzeOp(Operation *op, OneShotAnalysisState &state, BufferizationStatistics *statistics=nullptr)
Analyze op and its nested ops.
LogicalResult insertTensorCopies(Operation *op, const OneShotBufferizationOptions &options, const BufferizationState &bufferizationState, BufferizationStatistics *statistics=nullptr)
Resolve RaW and other conflicts by inserting bufferization.alloc_tensor ops.
LogicalResult runOneShotBufferize(Operation *op, const OneShotBufferizationOptions &options, BufferizationState &state, BufferizationStatistics *statistics=nullptr)
Run One-Shot Bufferize on the given op: Analysis + Bufferization.
Include the generated interface declarations.
llvm::DenseSet< ValueT, ValueInfoT > DenseSet
llvm::SetVector< T, Vector, Set, N > SetVector
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
llvm::function_ref< Fn > function_ref
This iterator enumerates elements in "reverse" order.
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