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<TensorType>(opOperand.
get().
getType()))
108 OpBuilder(op).getStrArrayAttr(inPlaceVector));
121 if (isa<TensorType>(v.getType()))
124 for (
Block &
b : r.getBlocks())
125 for (
auto bbArg :
b.getArguments())
126 if (isa<TensorType>(bbArg.getType()))
131 op->
walk([&](BufferizableOpInterface bufferizableOp) {
132 if (!
options.isOpAllowed(bufferizableOp))
134 for (
OpOperand &opOperand : bufferizableOp->getOpOperands())
135 if (isa<TensorType>(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<TensorType>(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 =
449 conflictingWritingOp->
setAttr(conflictingWriteAttr,
b.getUnitAttr());
451 std::string readAttr =
453 readingOp->
setAttr(readAttr,
b.getUnitAttr());
455 if (
auto opResult = dyn_cast<OpResult>(definition)) {
456 std::string defAttr =
457 id +
"[DEF: result " + std::to_string(opResult.getResultNumber()) +
"]";
458 opResult.getDefiningOp()->setAttr(defAttr,
b.getUnitAttr());
460 auto bbArg = cast<BlockArgument>(definition);
461 std::string defAttr =
462 id +
"[DEF: bbArg " + std::to_string(bbArg.getArgNumber()) +
"]";
463 bbArg.getOwner()->getParentOp()->setAttr(defAttr,
b.getUnitAttr());
478 TraversalConfig config;
479 config.followEquivalentOnly =
true;
480 config.alwaysIncludeLeaves =
false;
481 config.followSameTypeOrCastsOnly =
true;
483 .findValueInReverseUseDefChain(
484 start, [&](
Value v) {
return v == other; }, config)
492 SubsetInsertionOpInterface subsetOp) {
493 auto matchingSubset = [&](
Value val) {
494 if (
auto opResult = dyn_cast<OpResult>(val))
495 if (subsetOp.isEquivalentSubset(opResult, [&](
Value v1,
Value v2) {
496 return state.areEquivalentBufferizedValues(v1, v2);
504 state.findValueInReverseUseDefChain(opOperand, matchingSubset);
505 return llvm::all_of(backwardSlice, matchingSubset);
521 if (
auto subsetOp = dyn_cast<SubsetInsertionOpInterface>(readingOp)) {
529 if (uRead == &subsetOp.getDestinationOperand() &&
545 if (uRead == &subsetOp.getSourceOperand() &&
546 uConflictingWrite == &subsetOp.getDestinationOperand() &&
561 dyn_cast<SubsetInsertionOpInterface>(conflictingWritingOp))
578 if (uConflictingWrite == &subsetOp.getDestinationOperand() &&
579 state.areEquivalentBufferizedValues(
580 uRead->
get(), subsetOp.getSourceOperand().get()) &&
604 if (
options.checkParallelRegions && !usesRead.empty()) {
605 for (
OpOperand *uConflictingWrite : usesWrite) {
613 state.findValueInReverseUseDefChain(uConflictingWrite, [&](
Value v) {
614 return state.bufferizesToMemoryWrite(v);
616 assert(!definitionsOrLeaves.empty() &&
617 "expected at least one definition or leaf");
621 for (
Value def : definitionsOrLeaves) {
622 if (getParallelRegion(def.getParentRegion(),
options) !=
623 getParallelRegion(uConflictingWrite->getOwner()->getParentRegion(),
625 LDBG() <<
"\n- bufferizes out-of-place due to parallel region:\n"
626 <<
" unConflictingWrite = operand "
627 << uConflictingWrite->getOperandNumber() <<
" of "
637 Operation *readingOp = uRead->getOwner();
638 LDBG() <<
"\n- check conflict:\n"
639 <<
" uRead = operand " << uRead->getOperandNumber() <<
" of "
653 if (definitions.empty()) {
655 LDBG() <<
" no conflict: read value has no definitions";
661 for (
OpOperand *uConflictingWrite : usesWrite) {
662 LDBG() <<
" unConflictingWrite = operand "
663 << uConflictingWrite->getOperandNumber() <<
" of "
671 LDBG() <<
"\n- useDominance = " << useDominance;
675 Operation *conflictingWritingOp = uConflictingWrite->getOwner();
686 if (
happensBefore(readingOp, conflictingWritingOp, domInfo)) {
687 LDBG() <<
" no conflict: read happens before write";
698 if (uConflictingWrite == uRead) {
699 LDBG() <<
" no conflict: read and write are same use";
708 if (state.insideMutuallyExclusiveRegions(readingOp,
709 conflictingWritingOp)) {
710 LDBG() <<
" no conflict: read and write are in "
711 "mutually exclusive regions";
718 if (conflictingWritingOp == readingOp) {
719 if (
auto bufferizableOp =
options.dynCastBufferizableOp(readingOp)) {
720 if (bufferizableOp.bufferizesToElementwiseAccess(
721 state, {uRead, uConflictingWrite})) {
723 state, uRead, uConflictingWrite->get()) ||
725 state, uConflictingWrite, uRead->get())) {
726 LDBG() <<
" no conflict: op bufferizes to element-wise access";
736 LDBG() <<
" no conflict: non-conflicting subsets";
741 if (
auto bufferizableOp =
options.dynCastBufferizableOp(readingOp)) {
742 if (bufferizableOp.isNotConflicting(uRead, uConflictingWrite, state)) {
743 LDBG() <<
" no conflict: op interace of reading op says 'no'";
748 if (conflictingWritingOp != readingOp) {
749 if (
auto bufferizableOp =
750 options.dynCastBufferizableOp(conflictingWritingOp)) {
751 if (bufferizableOp.isNotConflicting(uRead, uConflictingWrite,
753 LDBG() <<
" no conflict: op interace of writing op says 'no'";
760 for (
Value definition : definitions) {
761 LDBG() <<
" * definition = " << definition;
764 if (
Operation *defOp = definition.getDefiningOp()) {
767 LDBG() <<
" no conflict: write happens before definition";
771 if (defOp->isProperAncestor(conflictingWritingOp)) {
772 LDBG() <<
" no conflict: write is contained in definition";
776 auto bbArg = cast<BlockArgument>(definition);
777 Block *block = bbArg.getOwner();
779 LDBG() <<
" no conflict: definition is bbArg "
780 "and write happens outside of block";
789 AliasingValueList aliases = state.getAliasingValues(*uConflictingWrite);
790 if (aliases.getNumAliases() == 1 &&
791 aliases.getAliases()[0].value == definition) {
792 LDBG() <<
" no conflict: definition and write are same";
800 LDBG() <<
" => RaW CONFLICT FOUND";
813 for (
auto &use : alias.
getUses())
824 for (
auto &use : alias.
getUses()) {
826 if (state.bufferizesToMemoryRead(use)) {
846 if (!state.bufferizesToMemoryWrite(use)) {
847 AliasingValueList aliases = state.getAliasingValues(use);
848 if (llvm::any_of(aliases, [&](AliasingValue a) {
849 return state.isValueRead(a.value);
893 for (AliasingValue alias : state.getAliasingValues(operand)) {
897 if (!checkConsistencyOnly && state.bufferizesToMemoryWrite(operand))
898 usesWrite.insert(&operand);
907 std::string
id =
"W_" + std::to_string(counter++);
908 if (
auto opResult = dyn_cast<OpResult>(value)) {
909 std::string attr =
id +
"[NOT-WRITABLE: result " +
910 std::to_string(opResult.getResultNumber()) +
"]";
911 opResult.getDefiningOp()->setAttr(attr,
b.getUnitAttr());
913 auto bbArg = cast<BlockArgument>(value);
914 std::string attr =
id +
"[NOT-WRITABLE: bbArg " +
915 std::to_string(bbArg.getArgNumber()) +
"]";
916 bbArg.getOwner()->getParentOp()->setAttr(attr,
b.getUnitAttr());
925 bool checkConsistencyOnly =
false) {
927 !checkConsistencyOnly && state.bufferizesToMemoryWrite(operand);
933 for (AliasingValue alias : state.getAliasingValues(operand))
935 foundWrite = !usesWrite.empty();
942 bool foundReadOnly =
false;
943 auto checkReadOnly = [&](
Value v) {
945 foundReadOnly =
true;
951 for (AliasingValue alias : state.getAliasingValues(operand))
954 LDBG() <<
"=> NOT WRITABLE";
966const llvm::SetVector<Value> &
969 if (!cachedDefinitions.count(value))
970 cachedDefinitions[value] = findDefinitions(opOperand);
971 return cachedDefinitions[value];
975 AnalysisState::resetCache();
976 cachedDefinitions.clear();
983 LDBG() <<
"//===-------------------------------------------===//\n"
987 bool foundInterference =
991 if (foundInterference)
996 LDBG() <<
"//===-------------------------------------------===//";
1004 if (isa<TensorType>(opOperand.get().getType()))
1014 if (
auto bufferizableOp = state.
getOptions().dynCastBufferizableOp(op)) {
1015 for (
OpResult opResult : op->getOpResults()) {
1016 if (!isa<TensorType>(opResult.getType()))
1018 AliasingOpOperandList aliases = state.getAliasingOpOperands(opResult);
1019 if (aliases.getNumAliases() == 0)
1023 Value firstOperand = aliases.begin()->opOperand->get();
1024 bool allEquivalent =
true;
1025 for (AliasingOpOperand alias : aliases) {
1026 bool isEquiv = alias.relation == BufferRelation::Equivalent;
1027 bool isInPlace = state.
isInPlace(*alias.opOperand);
1028 Value operand = alias.opOperand->get();
1029 if (isEquiv && isInPlace && alias.isDefinite) {
1033 allEquivalent =
false;
1036 if (!isEquiv || !isInPlace)
1037 allEquivalent =
false;
1039 allEquivalent =
false;
1052 if (allEquivalent && !bufferizableOp.bufferizesToAllocation(opResult))
1075static SmallVector<Operation *>
1082 if (!traversedOps.insert(term))
1087 for (
Value v : term->getOperands()) {
1088 if (!isa<TensorType>(v.
getType()))
1090 auto opResult = dyn_cast<OpResult>(v);
1093 worklist.push_back(opResult);
1095 while (!worklist.empty()) {
1096 OpResult opResult = worklist.pop_back_val();
1098 if (!traversedOps.insert(defOp))
1100 if (!term->getParentRegion()->findAncestorOpInRegion(*defOp))
1102 AliasingOpOperandList aliases = state.getAliasingOpOperands(opResult);
1103 for (
auto alias : aliases) {
1104 Value v = alias.opOperand->get();
1105 if (!isa<TensorType>(v.
getType()))
1107 auto opResult = dyn_cast<OpResult>(v);
1110 worklist.push_back(opResult);
1118 if (!traversedOps.contains(op) && hasTensorSemantics(op))
1136 if (!hasTensorSemantics(op))
1138 orderedOps.push_back(op);
1140 switch (heuristic) {
1143 std::reverse(orderedOps.begin(), orderedOps.end());
1152 "expected that fuzzer seed it set");
1157 std::mt19937 g(
getOptions().analysisFuzzerSeed);
1158 llvm::shuffle(orderedOps.begin(), orderedOps.end(), g);
1162 llvm_unreachable(
"unsupported heuristic");
1186 WalkResult walkResult = op->
walk([&](BufferizableOpInterface op) {
1188 if (!
options.isOpAllowed(op.getOperation()))
1192 if (!op.supportsUnstructuredControlFlow()) {
1194 if (r.getBlocks().size() > 1) {
1195 op->
emitOpError(
"op or BufferizableOpInterface implementation does "
1196 "not support unstructured control flow, but at least "
1197 "one region has multiple blocks");
1208 walkResult = op->
walk([&](BufferizableOpInterface op) {
1210 if (!
options.isOpAllowed(op.getOperation()))
1216 if (
auto toTensorOp = dyn_cast<ToTensorOp>(op.getOperation())) {
1217 if (!toTensorOp.getRestrict() && !toTensorOp->getUses().empty()) {
1218 op->
emitOpError(
"to_tensor ops without `restrict` are not supported by "
1219 "One-Shot Analysis");
1225 if (isa<TensorType>(opOperand.get().getType())) {
1227 opOperand, domInfo, state,
1234 op->
emitOpError(
"not bufferizable under the given constraints: "
1235 "cannot avoid RaW conflict");
1241 opOperand, state,
true)) {
1242 op->
emitOpError(
"not bufferizable under the given constraints: would "
1243 "write to read-only buffer");
1262 if (isa<TensorType>(opOperand.get().getType()))
1272 auto buildAliasesArray = [&](
Value v) {
1276 llvm::raw_string_ostream stream(buffer);
1278 aliases.push_back(
b.getStringAttr(buffer));
1280 return b.getArrayAttr(aliases);
1287 if (llvm::isa<TensorType>(opResult.getType())) {
1288 opResultAliasSets.push_back(buildAliasesArray(opResult));
1291 if (!opResultAliasSets.empty())
1296 bool hasTensorBbArg =
false;
1299 for (
Block &block : r.getBlocks()) {
1302 if (llvm::isa<TensorType>(bbArg.getType())) {
1303 bbArgAliasSets.push_back(buildAliasesArray(bbArg));
1304 hasTensorBbArg =
true;
1307 blockAliasSets.push_back(
b.getArrayAttr(bbArgAliasSets));
1309 regionAliasSets.push_back(
b.getArrayAttr(blockAliasSets));
1326 if (failed(state.
analyzeOp(op, domInfo)))
1334 bool failedAnalysis =
false;
1343 if (BufferizableOpInterface bufferizableOp =
1344 options.dynCastBufferizableOp(op))
1345 failedAnalysis |= failed(bufferizableOp.verifyAnalysis(state));
1354 return success(!failedAnalysis);
1363 "invalid combination of bufferization flags");
1365 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.
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