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>()));
98 if (isa<TensorType>(opOperand.
get().
getType()))
103 OpBuilder(op).getStrArrayAttr(inPlaceVector));
116 if (isa<TensorType>(v.getType()))
119 for (
Block &b : r.getBlocks())
120 for (
auto bbArg : b.getArguments())
121 if (isa<TensorType>(bbArg.getType()))
126 op->
walk([&](BufferizableOpInterface bufferizableOp) {
129 for (
OpOperand &opOperand : bufferizableOp->getOpOperands())
130 if (isa<TensorType>(opOperand.get().getType()))
131 if (bufferizableOp.mustBufferizeInPlace(opOperand, *
this))
139 auto leaderIt = equivalentInfo.findLeader(v);
140 for (
auto mit = leaderIt, meit = equivalentInfo.member_end(); mit != meit;
148 auto leaderIt = aliasInfo.findLeader(v);
149 for (
auto mit = leaderIt, meit = aliasInfo.member_end(); mit != meit; ++mit) {
156 return equivalentInfo.isEquivalent(v1, v2);
161 return aliasInfo.isEquivalent(v1, v2);
165 if (inplaceBufferized.contains(&operand))
167 inplaceBufferized.insert(&operand);
169 aliasInfo.unionSets(alias.value, operand.
get());
170 ++statNumTensorInPlace;
174 assert(!inplaceBufferized.contains(&operand) &&
175 "OpOperand was already decided to bufferize inplace");
176 ++statNumTensorOutOfPlace;
181 equivalentInfo.insert(v);
193 if (!isa<TensorType>(opResult.getType()))
198 if (opResult.getUses().empty())
202 OpOperand *opOperand = &(*opResult.getUses().begin());
204 for (
OpOperand &use : opResult.getUses())
205 undefinedTensorUses.insert(&use);
213 return undefinedTensorUses.contains(opOperand);
217 return inplaceBufferized.contains(&opOperand);
221 bool isWritten =
false;
233 if (
auto bufferizableOp =
235 return bufferizableOp.isWritable(value, *
this);
242 aliasInfo.unionSets(v1, v2);
246 equivalentInfo.unionSets(v1, v2);
259 if (!state.bufferizesToMemoryWrite(opOperand))
262 return state.isInPlace(opOperand);
359 for (
Value def : definitions) {
362 Region *rDef = state.getEnclosingRepetitiveRegion(def,
options);
373 if (nextRegion == rDef)
375 assert(nextRegion &&
"expected to find another repetitive region");
413 for (
Value def : definitions) {
414 Block *defBlock = def.getParentBlock();
415 if (readBlock->
isReachable(writeBlock, {defBlock}) &&
433 static uint64_t counter = 0;
438 std::string
id =
"C_" + std::to_string(counter++);
440 std::string conflictingWriteAttr =
446 std::string readAttr =
450 if (
auto opResult = dyn_cast<OpResult>(definition)) {
451 std::string defAttr =
452 id +
"[DEF: result " + std::to_string(opResult.getResultNumber()) +
"]";
453 opResult.getDefiningOp()->setAttr(defAttr, b.
getUnitAttr());
455 auto bbArg = cast<BlockArgument>(definition);
456 std::string defAttr =
457 id +
"[DEF: bbArg " + std::to_string(bbArg.getArgNumber()) +
"]";
458 bbArg.getOwner()->getParentOp()->setAttr(defAttr, b.
getUnitAttr());
474 config.followEquivalentOnly =
true;
475 config.alwaysIncludeLeaves =
false;
476 config.followSameTypeOrCastsOnly =
true;
478 .findValueInReverseUseDefChain(
479 start, [&](
Value v) {
return v == other; },
config)
487 SubsetInsertionOpInterface subsetOp) {
488 auto matchingSubset = [&](
Value val) {
489 if (
auto opResult = dyn_cast<OpResult>(val))
490 if (subsetOp.isEquivalentSubset(opResult, [&](
Value v1,
Value v2) {
491 return state.areEquivalentBufferizedValues(v1, v2);
499 state.findValueInReverseUseDefChain(opOperand, matchingSubset);
500 return static_cast<bool>(llvm::all_of(backwardSlice, matchingSubset));
516 if (
auto subsetOp = dyn_cast<SubsetInsertionOpInterface>(readingOp)) {
524 if (uRead == &subsetOp.getDestinationOperand() &&
540 if (uRead == &subsetOp.getSourceOperand() &&
541 uConflictingWrite == &subsetOp.getDestinationOperand() &&
556 dyn_cast<SubsetInsertionOpInterface>(conflictingWritingOp))
573 if (uConflictingWrite == &subsetOp.getDestinationOperand() &&
574 state.areEquivalentBufferizedValues(
575 uRead->
get(), subsetOp.getSourceOperand().get()) &&
599 if (
options.checkParallelRegions && !usesRead.empty()) {
600 for (
OpOperand *uConflictingWrite : usesWrite) {
608 state.findValueInReverseUseDefChain(uConflictingWrite, [&](
Value v) {
609 return state.bufferizesToMemoryWrite(v);
611 assert(!definitionsOrLeaves.empty() &&
612 "expected at least one definition or leaf");
616 for (
Value def : definitionsOrLeaves) {
620 LDBG() <<
"\n- bufferizes out-of-place due to parallel region:\n"
621 <<
" unConflictingWrite = operand "
622 << uConflictingWrite->getOperandNumber() <<
" of "
623 << *uConflictingWrite->getOwner();
631 Operation *readingOp = uRead->getOwner();
632 LDBG() <<
"\n- check conflict:\n"
633 <<
" uRead = operand " << uRead->getOperandNumber() <<
" of "
647 if (definitions.empty()) {
649 LDBG() <<
" no conflict: read value has no definitions";
655 for (
OpOperand *uConflictingWrite : usesWrite) {
656 LDBG() <<
" unConflictingWrite = operand "
657 << uConflictingWrite->getOperandNumber() <<
" of "
658 << *uConflictingWrite->getOwner();
664 LDBG() <<
"\n- useDominance = " << useDominance;
668 Operation *conflictingWritingOp = uConflictingWrite->getOwner();
679 if (
happensBefore(readingOp, conflictingWritingOp, domInfo)) {
680 LDBG() <<
" no conflict: read happens before write";
691 if (uConflictingWrite == uRead) {
692 LDBG() <<
" no conflict: read and write are same use";
701 if (state.insideMutuallyExclusiveRegions(readingOp,
702 conflictingWritingOp)) {
703 LDBG() <<
" no conflict: read and write are in "
704 "mutually exclusive regions";
711 if (conflictingWritingOp == readingOp) {
712 if (
auto bufferizableOp =
options.dynCastBufferizableOp(readingOp)) {
713 if (bufferizableOp.bufferizesToElementwiseAccess(
714 state, {uRead, uConflictingWrite})) {
716 state, uRead, uConflictingWrite->get()) ||
718 state, uConflictingWrite, uRead->get())) {
719 LDBG() <<
" no conflict: op bufferizes to element-wise access";
729 LDBG() <<
" no conflict: non-conflicting subsets";
734 if (
auto bufferizableOp =
options.dynCastBufferizableOp(readingOp)) {
735 if (bufferizableOp.isNotConflicting(uRead, uConflictingWrite, state)) {
736 LDBG() <<
" no conflict: op interace of reading op says 'no'";
741 if (conflictingWritingOp != readingOp) {
742 if (
auto bufferizableOp =
743 options.dynCastBufferizableOp(conflictingWritingOp)) {
744 if (bufferizableOp.isNotConflicting(uRead, uConflictingWrite,
746 LDBG() <<
" no conflict: op interace of writing op says 'no'";
753 for (
Value definition : definitions) {
754 LDBG() <<
" * definition = " << definition;
757 if (
Operation *defOp = definition.getDefiningOp()) {
760 LDBG() <<
" no conflict: write happens before definition";
764 if (defOp->isProperAncestor(conflictingWritingOp)) {
765 LDBG() <<
" no conflict: write is contained in definition";
769 auto bbArg = cast<BlockArgument>(definition);
770 Block *block = bbArg.getOwner();
772 LDBG() <<
" no conflict: definition is bbArg "
773 "and write happens outside of block";
784 aliases.
getAliases()[0].value == definition) {
785 LDBG() <<
" no conflict: definition and write are same";
793 LDBG() <<
" => RaW CONFLICT FOUND";
805 state.applyOnAliases(root, [&](
Value alias) {
806 for (
auto &use : alias.
getUses())
816 state.applyOnAliases(root, [&](
Value alias) {
817 for (
auto &use : alias.
getUses()) {
819 if (state.bufferizesToMemoryRead(use)) {
839 if (!state.bufferizesToMemoryWrite(use)) {
840 AliasingValueList aliases = state.getAliasingValues(use);
841 if (llvm::any_of(aliases, [&](AliasingValue a) {
842 return state.isValueRead(a.value);
886 for (
AliasingValue alias : state.getAliasingValues(operand)) {
890 if (!checkConsistencyOnly && state.bufferizesToMemoryWrite(operand))
891 usesWrite.insert(&operand);
898 static int64_t counter = 0;
900 std::string
id =
"W_" + std::to_string(counter++);
901 if (
auto opResult = dyn_cast<OpResult>(value)) {
902 std::string attr =
id +
"[NOT-WRITABLE: result " +
903 std::to_string(opResult.getResultNumber()) +
"]";
904 opResult.getDefiningOp()->setAttr(attr, b.
getUnitAttr());
906 auto bbArg = cast<BlockArgument>(value);
907 std::string attr =
id +
"[NOT-WRITABLE: bbArg " +
908 std::to_string(bbArg.getArgNumber()) +
"]";
909 bbArg.getOwner()->getParentOp()->setAttr(attr, b.
getUnitAttr());
918 bool checkConsistencyOnly =
false) {
920 !checkConsistencyOnly && state.bufferizesToMemoryWrite(operand);
928 foundWrite = !usesWrite.empty();
935 bool foundReadOnly =
false;
936 auto checkReadOnly = [&](
Value v) {
937 if (!state.isWritable(v)) {
938 foundReadOnly =
true;
939 if (state.getOptions().printConflicts)
943 state.applyOnAliases(operand.
get(), checkReadOnly);
945 state.applyOnAliases(alias.value, checkReadOnly);
947 LDBG() <<
"=> NOT WRITABLE";
960 OneShotAnalysisState::findDefinitionsCached(
OpOperand *opOperand) {
962 if (!cachedDefinitions.count(value))
964 return cachedDefinitions[value];
969 cachedDefinitions.clear();
976 LDBG() <<
"//===-------------------------------------------===//\n"
980 bool foundInterference =
984 if (foundInterference)
985 state.bufferizeOutOfPlace(operand);
987 state.bufferizeInPlace(operand);
989 LDBG() <<
"//===-------------------------------------------===//";
997 if (isa<TensorType>(opOperand.get().getType()))
1007 if (
auto bufferizableOp = state.getOptions().dynCastBufferizableOp(op)) {
1008 for (
OpResult opResult : op->getOpResults()) {
1009 if (!isa<TensorType>(opResult.getType()))
1016 Value firstOperand = aliases.
begin()->opOperand->get();
1017 bool allEquivalent =
true;
1020 bool isInPlace = state.isInPlace(*alias.opOperand);
1021 Value operand = alias.opOperand->get();
1022 if (isEquiv && isInPlace && alias.isDefinite) {
1025 state.unionEquivalenceClasses(opResult, operand);
1026 allEquivalent =
false;
1029 if (!isEquiv || !isInPlace)
1030 allEquivalent =
false;
1031 if (!state.areEquivalentBufferizedValues(operand, firstOperand))
1032 allEquivalent =
false;
1045 if (allEquivalent && !bufferizableOp.bufferizesToAllocation(opResult))
1046 state.unionEquivalenceClasses(opResult, firstOperand);
1075 if (!traversedOps.insert(term))
1080 for (
Value v : term->getOperands()) {
1081 if (!isa<TensorType>(v.getType()))
1083 auto opResult = dyn_cast<OpResult>(v);
1086 worklist.push_back(opResult);
1088 while (!worklist.empty()) {
1089 OpResult opResult = worklist.pop_back_val();
1091 if (!traversedOps.insert(defOp))
1093 if (!term->getParentRegion()->findAncestorOpInRegion(*defOp))
1096 for (
auto alias : aliases) {
1097 Value v = alias.opOperand->get();
1098 if (!isa<TensorType>(v.
getType()))
1100 auto opResult = dyn_cast<OpResult>(v);
1103 worklist.push_back(opResult);
1112 result.push_back(op);
1131 orderedOps.push_back(op);
1133 switch (heuristic) {
1136 std::reverse(orderedOps.begin(), orderedOps.end());
1145 "expected that fuzzer seed it set");
1150 std::mt19937 g(
getOptions().analysisFuzzerSeed);
1151 llvm::shuffle(orderedOps.begin(), orderedOps.end(), g);
1155 llvm_unreachable(
"unsupported heuristic");
1171 static LogicalResult
1179 WalkResult walkResult = op->
walk([&](BufferizableOpInterface op) {
1181 if (!
options.isOpAllowed(op.getOperation()))
1185 if (!op.supportsUnstructuredControlFlow()) {
1186 for (Region &r : op->getRegions()) {
1187 if (r.getBlocks().size() > 1) {
1188 op->emitOpError(
"op or BufferizableOpInterface implementation does "
1189 "not support unstructured control flow, but at least "
1190 "one region has multiple blocks");
1191 return WalkResult::interrupt();
1198 if (walkResult.wasInterrupted())
1201 walkResult = op->walk([&](BufferizableOpInterface op) {
1203 if (!
options.isOpAllowed(op.getOperation()))
1209 if (
auto toTensorOp = dyn_cast<ToTensorOp>(op.getOperation())) {
1210 if (!toTensorOp.getRestrict() && !toTensorOp->getUses().empty()) {
1211 op->emitOpError(
"to_tensor ops without `restrict` are not supported by "
1212 "One-Shot Analysis");
1217 for (
OpOperand &opOperand : op->getOpOperands()) {
1218 if (isa<TensorType>(opOperand.get().getType())) {
1220 opOperand, domInfo, state,
1227 op->emitOpError(
"not bufferizable under the given constraints: "
1228 "cannot avoid RaW conflict");
1232 if (state.isInPlace(opOperand) &&
1234 opOperand, state,
true)) {
1235 op->emitOpError(
"not bufferizable under the given constraints: would "
1236 "write to read-only buffer");
1245 return success(!walkResult.wasInterrupted());
1255 if (isa<TensorType>(opOperand.get().getType()))
1265 auto buildAliasesArray = [&](
Value v) {
1267 state.applyOnAliases(v, [&](
Value alias) {
1269 llvm::raw_string_ostream stream(buffer);
1280 if (llvm::isa<TensorType>(opResult.getType())) {
1281 opResultAliasSets.push_back(buildAliasesArray(opResult));
1284 if (!opResultAliasSets.empty())
1289 bool hasTensorBbArg =
false;
1292 for (
Block &block : r.getBlocks()) {
1295 if (llvm::isa<TensorType>(bbArg.getType())) {
1296 bbArgAliasSets.push_back(buildAliasesArray(bbArg));
1297 hasTensorBbArg =
true;
1300 blockAliasSets.push_back(b.
getArrayAttr(bbArgAliasSets));
1302 regionAliasSets.push_back(b.
getArrayAttr(blockAliasSets));
1319 if (
failed(state.analyzeOp(op, domInfo)))
1327 bool failedAnalysis =
false;
1330 state.gatherUndefinedTensorUses(op);
1336 if (BufferizableOpInterface bufferizableOp =
1337 options.dynCastBufferizableOp(op))
1338 failedAnalysis |=
failed(bufferizableOp.verifyAnalysis(state));
1347 return success(!failedAnalysis);
1356 "invalid combination of bufferization flags");
1358 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.
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)
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 ...
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,...
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.
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(OpOperand *opOperand) const
Find the values that may define the contents of the given value at runtime.
virtual void resetCache()
BufferizationState provides information about the state of the IR during the bufferization process.
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.
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 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.
Operation * getOwnerOfValue(Value value)
Return the owner of the given value.
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.
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.
const FrozenRewritePatternSet GreedyRewriteConfig config
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.