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) {
127 if (!
options.isOpAllowed(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);
168 for (AliasingValue alias : getAliasingValues(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);
187 auto bufferizableOp =
getOptions().dynCastBufferizableOp(op);
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;
224 if (
isInPlace(use) && bufferizesToMemoryWrite(use))
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))
359 for (
Value def : definitions) {
362 Region *rDef = state.getEnclosingRepetitiveRegion(def,
options);
372 Region *nextRegion = getNextEnclosingRepetitiveRegion(rRead,
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 =
444 conflictingWritingOp->
setAttr(conflictingWriteAttr,
b.getUnitAttr());
446 std::string readAttr =
448 readingOp->
setAttr(readAttr,
b.getUnitAttr());
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 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) {
617 if (getParallelRegion(def.getParentRegion(),
options) !=
618 getParallelRegion(uConflictingWrite->getOwner()->getParentRegion(),
620 LDBG() <<
"\n- bufferizes out-of-place due to parallel region:\n"
621 <<
" unConflictingWrite = operand "
622 << uConflictingWrite->getOperandNumber() <<
" of "
632 Operation *readingOp = uRead->getOwner();
633 LDBG() <<
"\n- check conflict:\n"
634 <<
" uRead = operand " << uRead->getOperandNumber() <<
" of "
648 if (definitions.empty()) {
650 LDBG() <<
" no conflict: read value has no definitions";
656 for (
OpOperand *uConflictingWrite : usesWrite) {
657 LDBG() <<
" unConflictingWrite = operand "
658 << uConflictingWrite->getOperandNumber() <<
" of "
666 LDBG() <<
"\n- useDominance = " << useDominance;
670 Operation *conflictingWritingOp = uConflictingWrite->getOwner();
681 if (
happensBefore(readingOp, conflictingWritingOp, domInfo)) {
682 LDBG() <<
" no conflict: read happens before write";
693 if (uConflictingWrite == uRead) {
694 LDBG() <<
" no conflict: read and write are same use";
703 if (state.insideMutuallyExclusiveRegions(readingOp,
704 conflictingWritingOp)) {
705 LDBG() <<
" no conflict: read and write are in "
706 "mutually exclusive regions";
713 if (conflictingWritingOp == readingOp) {
714 if (
auto bufferizableOp =
options.dynCastBufferizableOp(readingOp)) {
715 if (bufferizableOp.bufferizesToElementwiseAccess(
716 state, {uRead, uConflictingWrite})) {
718 state, uRead, uConflictingWrite->get()) ||
720 state, uConflictingWrite, uRead->get())) {
721 LDBG() <<
" no conflict: op bufferizes to element-wise access";
731 LDBG() <<
" no conflict: non-conflicting subsets";
736 if (
auto bufferizableOp =
options.dynCastBufferizableOp(readingOp)) {
737 if (bufferizableOp.isNotConflicting(uRead, uConflictingWrite, state)) {
738 LDBG() <<
" no conflict: op interace of reading op says 'no'";
743 if (conflictingWritingOp != readingOp) {
744 if (
auto bufferizableOp =
745 options.dynCastBufferizableOp(conflictingWritingOp)) {
746 if (bufferizableOp.isNotConflicting(uRead, uConflictingWrite,
748 LDBG() <<
" no conflict: op interace of writing op says 'no'";
755 for (
Value definition : definitions) {
756 LDBG() <<
" * definition = " << definition;
759 if (
Operation *defOp = definition.getDefiningOp()) {
762 LDBG() <<
" no conflict: write happens before definition";
766 if (defOp->isProperAncestor(conflictingWritingOp)) {
767 LDBG() <<
" no conflict: write is contained in definition";
771 auto bbArg = cast<BlockArgument>(definition);
772 Block *block = bbArg.getOwner();
774 LDBG() <<
" no conflict: definition is bbArg "
775 "and write happens outside of block";
784 AliasingValueList aliases = state.getAliasingValues(*uConflictingWrite);
785 if (aliases.getNumAliases() == 1 &&
786 aliases.getAliases()[0].value == definition) {
787 LDBG() <<
" no conflict: definition and write are same";
795 LDBG() <<
" => RaW CONFLICT FOUND";
808 for (
auto &use : alias.
getUses())
819 for (
auto &use : alias.
getUses()) {
821 if (state.bufferizesToMemoryRead(use)) {
841 if (!state.bufferizesToMemoryWrite(use)) {
842 AliasingValueList aliases = state.getAliasingValues(use);
843 if (llvm::any_of(aliases, [&](AliasingValue a) {
844 return state.isValueRead(a.value);
888 for (AliasingValue alias : state.getAliasingValues(operand)) {
892 if (!checkConsistencyOnly && state.bufferizesToMemoryWrite(operand))
893 usesWrite.insert(&operand);
902 std::string
id =
"W_" + std::to_string(counter++);
903 if (
auto opResult = dyn_cast<OpResult>(value)) {
904 std::string attr =
id +
"[NOT-WRITABLE: result " +
905 std::to_string(opResult.getResultNumber()) +
"]";
906 opResult.getDefiningOp()->setAttr(attr,
b.getUnitAttr());
908 auto bbArg = cast<BlockArgument>(value);
909 std::string attr =
id +
"[NOT-WRITABLE: bbArg " +
910 std::to_string(bbArg.getArgNumber()) +
"]";
911 bbArg.getOwner()->getParentOp()->setAttr(attr,
b.getUnitAttr());
920 bool checkConsistencyOnly =
false) {
922 !checkConsistencyOnly && state.bufferizesToMemoryWrite(operand);
928 for (AliasingValue alias : state.getAliasingValues(operand))
930 foundWrite = !usesWrite.empty();
937 bool foundReadOnly =
false;
938 auto checkReadOnly = [&](
Value v) {
940 foundReadOnly =
true;
946 for (AliasingValue alias : state.getAliasingValues(operand))
949 LDBG() <<
"=> NOT WRITABLE";
961const llvm::SetVector<Value> &
964 if (!cachedDefinitions.count(value))
965 cachedDefinitions[value] = findDefinitions(opOperand);
966 return cachedDefinitions[value];
970 AnalysisState::resetCache();
971 cachedDefinitions.clear();
978 LDBG() <<
"//===-------------------------------------------===//\n"
982 bool foundInterference =
986 if (foundInterference)
991 LDBG() <<
"//===-------------------------------------------===//";
999 if (isa<TensorType>(opOperand.get().getType()))
1009 if (
auto bufferizableOp = state.
getOptions().dynCastBufferizableOp(op)) {
1010 for (
OpResult opResult : op->getOpResults()) {
1011 if (!isa<TensorType>(opResult.getType()))
1013 AliasingOpOperandList aliases = state.getAliasingOpOperands(opResult);
1014 if (aliases.getNumAliases() == 0)
1018 Value firstOperand = aliases.begin()->opOperand->get();
1019 bool allEquivalent =
true;
1020 for (AliasingOpOperand alias : aliases) {
1021 bool isEquiv = alias.relation == BufferRelation::Equivalent;
1022 bool isInPlace = state.
isInPlace(*alias.opOperand);
1023 Value operand = alias.opOperand->get();
1024 if (isEquiv && isInPlace && alias.isDefinite) {
1028 allEquivalent =
false;
1031 if (!isEquiv || !isInPlace)
1032 allEquivalent =
false;
1034 allEquivalent =
false;
1047 if (allEquivalent && !bufferizableOp.bufferizesToAllocation(opResult))
1070static SmallVector<Operation *>
1077 if (!traversedOps.insert(term))
1082 for (
Value v : term->getOperands()) {
1083 if (!isa<TensorType>(v.
getType()))
1085 auto opResult = dyn_cast<OpResult>(v);
1088 worklist.push_back(opResult);
1090 while (!worklist.empty()) {
1091 OpResult opResult = worklist.pop_back_val();
1093 if (!traversedOps.insert(defOp))
1095 if (!term->getParentRegion()->findAncestorOpInRegion(*defOp))
1097 AliasingOpOperandList aliases = state.getAliasingOpOperands(opResult);
1098 for (
auto alias : aliases) {
1099 Value v = alias.opOperand->get();
1100 if (!isa<TensorType>(v.
getType()))
1102 auto opResult = dyn_cast<OpResult>(v);
1105 worklist.push_back(opResult);
1113 if (!traversedOps.contains(op) && hasTensorSemantics(op))
1131 if (!hasTensorSemantics(op))
1133 orderedOps.push_back(op);
1135 switch (heuristic) {
1138 std::reverse(orderedOps.begin(), orderedOps.end());
1147 "expected that fuzzer seed it set");
1152 std::mt19937 g(
getOptions().analysisFuzzerSeed);
1153 llvm::shuffle(orderedOps.begin(), orderedOps.end(), g);
1157 llvm_unreachable(
"unsupported heuristic");
1181 WalkResult walkResult = op->
walk([&](BufferizableOpInterface op) {
1183 if (!
options.isOpAllowed(op.getOperation()))
1187 if (!op.supportsUnstructuredControlFlow()) {
1189 if (r.getBlocks().size() > 1) {
1190 op->
emitOpError(
"op or BufferizableOpInterface implementation does "
1191 "not support unstructured control flow, but at least "
1192 "one region has multiple blocks");
1203 walkResult = op->
walk([&](BufferizableOpInterface op) {
1205 if (!
options.isOpAllowed(op.getOperation()))
1211 if (
auto toTensorOp = dyn_cast<ToTensorOp>(op.getOperation())) {
1212 if (!toTensorOp.getRestrict() && !toTensorOp->getUses().empty()) {
1213 op->
emitOpError(
"to_tensor ops without `restrict` are not supported by "
1214 "One-Shot Analysis");
1220 if (isa<TensorType>(opOperand.get().getType())) {
1222 opOperand, domInfo, state,
1229 op->
emitOpError(
"not bufferizable under the given constraints: "
1230 "cannot avoid RaW conflict");
1236 opOperand, state,
true)) {
1237 op->
emitOpError(
"not bufferizable under the given constraints: would "
1238 "write to read-only buffer");
1257 if (isa<TensorType>(opOperand.get().getType()))
1267 auto buildAliasesArray = [&](
Value v) {
1271 llvm::raw_string_ostream stream(buffer);
1273 aliases.push_back(
b.getStringAttr(buffer));
1275 return b.getArrayAttr(aliases);
1282 if (llvm::isa<TensorType>(opResult.getType())) {
1283 opResultAliasSets.push_back(buildAliasesArray(opResult));
1286 if (!opResultAliasSets.empty())
1291 bool hasTensorBbArg =
false;
1294 for (
Block &block : r.getBlocks()) {
1297 if (llvm::isa<TensorType>(bbArg.getType())) {
1298 bbArgAliasSets.push_back(buildAliasesArray(bbArg));
1299 hasTensorBbArg =
true;
1302 blockAliasSets.push_back(
b.getArrayAttr(bbArgAliasSets));
1304 regionAliasSets.push_back(
b.getArrayAttr(blockAliasSets));
1321 if (failed(state.
analyzeOp(op, domInfo)))
1329 bool failedAnalysis =
false;
1338 if (BufferizableOpInterface bufferizableOp =
1339 options.dynCastBufferizableOp(op))
1340 failedAnalysis |= failed(bufferizableOp.verifyAnalysis(state));
1349 return success(!failedAnalysis);
1358 "invalid combination of bufferization flags");
1360 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.
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()
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 getAttr(StringAttr name)
Return the specified attribute if present, null otherwise.
Block * getBlock()
Returns the operation block that contains this operation.
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
MutableArrayRef< OpOperand > getOpOperands()
unsigned getNumOperands()
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.
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.
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.
const FrozenRewritePatternSet GreedyRewriteConfig config
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