57 #include "llvm/ADT/DenseSet.h"
58 #include "llvm/ADT/SetVector.h"
64 #define DEBUG_TYPE "one-shot-analysis"
83 "__opresult_alias_set_attr__";
93 cast<ArrayAttr>(attr).getAsValueRange<StringAttr>()));
97 if (isa<TensorType>(opOperand.
get().
getType()))
102 OpBuilder(op).getStrArrayAttr(inPlaceVector));
115 if (isa<TensorType>(v.getType()))
118 for (
Block &b : r.getBlocks())
119 for (
auto bbArg : b.getArguments())
120 if (isa<TensorType>(bbArg.getType()))
125 op->
walk([&](BufferizableOpInterface bufferizableOp) {
128 for (
OpOperand &opOperand : bufferizableOp->getOpOperands())
129 if (isa<TensorType>(opOperand.get().getType()))
130 if (bufferizableOp.mustBufferizeInPlace(opOperand, *
this))
138 auto leaderIt = equivalentInfo.findLeader(v);
139 for (
auto mit = leaderIt, meit = equivalentInfo.member_end(); mit != meit;
147 auto leaderIt = aliasInfo.findLeader(v);
148 for (
auto mit = leaderIt, meit = aliasInfo.member_end(); mit != meit; ++mit) {
155 return equivalentInfo.isEquivalent(v1, v2);
160 return aliasInfo.isEquivalent(v1, v2);
164 if (inplaceBufferized.contains(&operand))
166 inplaceBufferized.insert(&operand);
168 aliasInfo.unionSets(alias.value, operand.
get());
169 ++statNumTensorInPlace;
173 assert(!inplaceBufferized.contains(&operand) &&
174 "OpOperand was already decided to bufferize inplace");
175 ++statNumTensorOutOfPlace;
180 equivalentInfo.insert(v);
192 if (!isa<TensorType>(opResult.getType()))
197 if (opResult.getUses().empty())
201 OpOperand *opOperand = &(*opResult.getUses().begin());
203 for (
OpOperand &use : opResult.getUses())
204 undefinedTensorUses.insert(&use);
212 return undefinedTensorUses.contains(opOperand);
216 return inplaceBufferized.contains(&opOperand);
220 bool isWritten =
false;
232 if (
auto bufferizableOp =
234 return bufferizableOp.isWritable(value, *
this);
241 aliasInfo.unionSets(v1, v2);
245 equivalentInfo.unionSets(v1, v2);
258 if (!state.bufferizesToMemoryWrite(opOperand))
261 return state.isInPlace(opOperand);
358 for (
Value def : definitions) {
361 Region *rDef = state.getEnclosingRepetitiveRegion(def,
options);
372 if (nextRegion == rDef)
374 assert(nextRegion &&
"expected to find another repetitive region");
412 for (
Value def : definitions) {
413 Block *defBlock = def.getParentBlock();
414 if (readBlock->
isReachable(writeBlock, {defBlock}) &&
432 static uint64_t counter = 0;
437 std::string
id =
"C_" + std::to_string(counter++);
439 std::string conflictingWriteAttr =
445 std::string readAttr =
449 if (
auto opResult = dyn_cast<OpResult>(definition)) {
450 std::string defAttr =
451 id +
"[DEF: result " + std::to_string(opResult.getResultNumber()) +
"]";
452 opResult.getDefiningOp()->setAttr(defAttr, b.
getUnitAttr());
454 auto bbArg = cast<BlockArgument>(definition);
455 std::string defAttr =
456 id +
"[DEF: bbArg " + std::to_string(bbArg.getArgNumber()) +
"]";
457 bbArg.getOwner()->getParentOp()->setAttr(defAttr, b.
getUnitAttr());
473 config.followEquivalentOnly =
true;
474 config.alwaysIncludeLeaves =
false;
475 config.followSameTypeOrCastsOnly =
true;
477 .findValueInReverseUseDefChain(
478 start, [&](
Value v) {
return v == other; },
config)
486 SubsetInsertionOpInterface subsetOp) {
487 auto matchingSubset = [&](
Value val) {
488 if (
auto opResult = dyn_cast<OpResult>(val))
489 if (subsetOp.isEquivalentSubset(opResult, [&](
Value v1,
Value v2) {
490 return state.areEquivalentBufferizedValues(v1, v2);
498 state.findValueInReverseUseDefChain(opOperand, matchingSubset);
499 return static_cast<bool>(llvm::all_of(backwardSlice, matchingSubset));
515 if (
auto subsetOp = dyn_cast<SubsetInsertionOpInterface>(readingOp)) {
523 if (uRead == &subsetOp.getDestinationOperand() &&
539 if (uRead == &subsetOp.getSourceOperand() &&
540 uConflictingWrite == &subsetOp.getDestinationOperand() &&
555 dyn_cast<SubsetInsertionOpInterface>(conflictingWritingOp))
572 if (uConflictingWrite == &subsetOp.getDestinationOperand() &&
573 state.areEquivalentBufferizedValues(
574 uRead->
get(), subsetOp.getSourceOperand().get()) &&
598 if (
options.checkParallelRegions && !usesRead.empty()) {
599 for (
OpOperand *uConflictingWrite : usesWrite) {
607 state.findValueInReverseUseDefChain(uConflictingWrite, [&](
Value v) {
608 return state.bufferizesToMemoryWrite(v);
610 assert(!definitionsOrLeaves.empty() &&
611 "expected at least one definition or leaf");
615 for (
Value def : definitionsOrLeaves) {
621 <<
"\n- bufferizes out-of-place due to parallel region:\n");
622 LLVM_DEBUG(llvm::dbgs()
623 <<
" unConflictingWrite = operand "
624 << uConflictingWrite->getOperandNumber() <<
" of "
625 << *uConflictingWrite->getOwner() <<
"\n");
633 Operation *readingOp = uRead->getOwner();
634 LLVM_DEBUG(llvm::dbgs() <<
"\n- check conflict:\n");
635 LLVM_DEBUG(llvm::dbgs() <<
" uRead = operand " << uRead->getOperandNumber()
636 <<
" of " << *readingOp <<
"\n");
649 if (definitions.empty()) {
651 LLVM_DEBUG(llvm::dbgs()
652 <<
" no conflict: read value has no definitions\n");
658 for (
OpOperand *uConflictingWrite : usesWrite) {
659 LLVM_DEBUG(llvm::dbgs() <<
" unConflictingWrite = operand "
660 << uConflictingWrite->getOperandNumber() <<
" of "
661 << *uConflictingWrite->getOwner() <<
"\n");
667 LLVM_DEBUG(llvm::dbgs() <<
"\n- useDominance = " << useDominance <<
"\n");
671 Operation *conflictingWritingOp = uConflictingWrite->getOwner();
682 if (
happensBefore(readingOp, conflictingWritingOp, domInfo)) {
683 LLVM_DEBUG(llvm::dbgs()
684 <<
" no conflict: read happens before write\n");
695 if (uConflictingWrite == uRead) {
696 LLVM_DEBUG(llvm::dbgs()
697 <<
" no conflict: read and write are same use\n");
706 if (state.insideMutuallyExclusiveRegions(readingOp,
707 conflictingWritingOp)) {
708 LLVM_DEBUG(llvm::dbgs() <<
" no conflict: read and write are in "
709 "mutually exclusive regions\n");
716 if (conflictingWritingOp == readingOp) {
717 if (
auto bufferizableOp =
options.dynCastBufferizableOp(readingOp)) {
718 if (bufferizableOp.bufferizesToElementwiseAccess(
719 state, {uRead, uConflictingWrite})) {
721 state, uRead, uConflictingWrite->get()) ||
723 state, uConflictingWrite, uRead->get())) {
726 <<
" no conflict: op bufferizes to element-wise access\n");
736 LLVM_DEBUG(llvm::dbgs() <<
" no conflict: non-conflicting subsets\n");
741 if (
auto bufferizableOp =
options.dynCastBufferizableOp(readingOp)) {
742 if (bufferizableOp.isNotConflicting(uRead, uConflictingWrite, state)) {
743 LLVM_DEBUG(llvm::dbgs()
744 <<
" no conflict: op interace of reading op says 'no'\n");
749 if (conflictingWritingOp != readingOp) {
750 if (
auto bufferizableOp =
751 options.dynCastBufferizableOp(conflictingWritingOp)) {
752 if (bufferizableOp.isNotConflicting(uRead, uConflictingWrite,
756 <<
" no conflict: op interace of writing op says 'no'\n");
763 for (
Value definition : definitions) {
764 LLVM_DEBUG(llvm::dbgs() <<
" * definition = " << definition <<
"\n");
767 if (
Operation *defOp = definition.getDefiningOp()) {
770 LLVM_DEBUG(llvm::dbgs()
771 <<
" no conflict: write happens before definition\n");
775 if (defOp->isProperAncestor(conflictingWritingOp)) {
778 <<
" no conflict: write is contained in definition\n");
782 auto bbArg = cast<BlockArgument>(definition);
783 Block *block = bbArg.getOwner();
785 LLVM_DEBUG(llvm::dbgs() <<
" no conflict: definition is bbArg "
786 "and write happens outside of block\n");
797 aliases.
getAliases()[0].value == definition) {
798 LLVM_DEBUG(llvm::dbgs()
799 <<
" no conflict: definition and write are same\n");
807 LLVM_DEBUG(llvm::dbgs() <<
" => RaW CONFLICT FOUND\n");
819 state.applyOnAliases(root, [&](
Value alias) {
820 for (
auto &use : alias.
getUses())
830 state.applyOnAliases(root, [&](
Value alias) {
831 for (
auto &use : alias.
getUses()) {
833 if (state.bufferizesToMemoryRead(use)) {
853 if (!state.bufferizesToMemoryWrite(use)) {
854 AliasingValueList aliases = state.getAliasingValues(use);
855 if (llvm::any_of(aliases, [&](AliasingValue a) {
856 return state.isValueRead(a.value);
900 for (
AliasingValue alias : state.getAliasingValues(operand)) {
904 if (!checkConsistencyOnly && state.bufferizesToMemoryWrite(operand))
905 usesWrite.insert(&operand);
912 static int64_t counter = 0;
914 std::string
id =
"W_" + std::to_string(counter++);
915 if (
auto opResult = dyn_cast<OpResult>(value)) {
916 std::string attr =
id +
"[NOT-WRITABLE: result " +
917 std::to_string(opResult.getResultNumber()) +
"]";
918 opResult.getDefiningOp()->setAttr(attr, b.
getUnitAttr());
920 auto bbArg = cast<BlockArgument>(value);
921 std::string attr =
id +
"[NOT-WRITABLE: bbArg " +
922 std::to_string(bbArg.getArgNumber()) +
"]";
923 bbArg.getOwner()->getParentOp()->setAttr(attr, b.
getUnitAttr());
932 bool checkConsistencyOnly =
false) {
934 !checkConsistencyOnly && state.bufferizesToMemoryWrite(operand);
942 foundWrite = !usesWrite.empty();
949 bool foundReadOnly =
false;
950 auto checkReadOnly = [&](
Value v) {
951 if (!state.isWritable(v)) {
952 foundReadOnly =
true;
953 if (state.getOptions().printConflicts)
957 state.applyOnAliases(operand.
get(), checkReadOnly);
959 state.applyOnAliases(alias.value, checkReadOnly);
961 LLVM_DEBUG(llvm::dbgs() <<
"=> NOT WRITABLE\n");
974 OneShotAnalysisState::findDefinitionsCached(
OpOperand *opOperand) {
976 if (!cachedDefinitions.count(value))
978 return cachedDefinitions[value];
983 cachedDefinitions.clear();
991 llvm::dbgs() <<
"//===-------------------------------------------===//\n"
993 <<
" of " << *operand.
getOwner() <<
"\n");
995 bool foundInterference =
999 if (foundInterference)
1000 state.bufferizeOutOfPlace(operand);
1002 state.bufferizeInPlace(operand);
1004 LLVM_DEBUG(llvm::dbgs()
1005 <<
"//===-------------------------------------------===//\n");
1013 if (isa<TensorType>(opOperand.get().getType()))
1023 if (
auto bufferizableOp = state.getOptions().dynCastBufferizableOp(op)) {
1024 for (
OpResult opResult : op->getOpResults()) {
1025 if (!isa<TensorType>(opResult.getType()))
1032 Value firstOperand = aliases.
begin()->opOperand->get();
1033 bool allEquivalent =
true;
1036 bool isInPlace = state.isInPlace(*alias.opOperand);
1037 Value operand = alias.opOperand->get();
1038 if (isEquiv && isInPlace && alias.isDefinite) {
1041 state.unionEquivalenceClasses(opResult, operand);
1042 allEquivalent =
false;
1045 if (!isEquiv || !isInPlace)
1046 allEquivalent =
false;
1047 if (!state.areEquivalentBufferizedValues(operand, firstOperand))
1048 allEquivalent =
false;
1061 if (allEquivalent && !bufferizableOp.bufferizesToAllocation(opResult))
1062 state.unionEquivalenceClasses(opResult, firstOperand);
1091 if (!traversedOps.insert(term))
1096 for (
Value v : term->getOperands()) {
1097 if (!isa<TensorType>(v.getType()))
1099 auto opResult = dyn_cast<OpResult>(v);
1102 worklist.push_back(opResult);
1104 while (!worklist.empty()) {
1105 OpResult opResult = worklist.pop_back_val();
1107 if (!traversedOps.insert(defOp))
1109 if (!term->getParentRegion()->findAncestorOpInRegion(*defOp))
1112 for (
auto alias : aliases) {
1113 Value v = alias.opOperand->get();
1114 if (!isa<TensorType>(v.
getType()))
1116 auto opResult = dyn_cast<OpResult>(v);
1119 worklist.push_back(opResult);
1128 result.push_back(op);
1147 orderedOps.push_back(op);
1149 switch (heuristic) {
1152 std::reverse(orderedOps.begin(), orderedOps.end());
1161 "expected that fuzzer seed it set");
1166 std::mt19937 g(
getOptions().analysisFuzzerSeed);
1167 llvm::shuffle(orderedOps.begin(), orderedOps.end(), g);
1171 llvm_unreachable(
"unsupported heuristic");
1187 static LogicalResult
1195 WalkResult walkResult = op->
walk([&](BufferizableOpInterface op) {
1197 if (!
options.isOpAllowed(op.getOperation()))
1201 if (!op.supportsUnstructuredControlFlow()) {
1202 for (Region &r : op->getRegions()) {
1203 if (r.getBlocks().size() > 1) {
1204 op->emitOpError(
"op or BufferizableOpInterface implementation does "
1205 "not support unstructured control flow, but at least "
1206 "one region has multiple blocks");
1207 return WalkResult::interrupt();
1214 if (walkResult.wasInterrupted())
1217 walkResult = op->walk([&](BufferizableOpInterface op) {
1219 if (!
options.isOpAllowed(op.getOperation()))
1225 if (
auto toTensorOp = dyn_cast<ToTensorOp>(op.getOperation())) {
1226 if (!toTensorOp.getRestrict() && !toTensorOp->getUses().empty()) {
1227 op->emitOpError(
"to_tensor ops without `restrict` are not supported by "
1228 "One-Shot Analysis");
1233 for (
OpOperand &opOperand : op->getOpOperands()) {
1234 if (isa<TensorType>(opOperand.get().getType())) {
1236 opOperand, domInfo, state,
1243 op->emitOpError(
"not bufferizable under the given constraints: "
1244 "cannot avoid RaW conflict");
1248 if (state.isInPlace(opOperand) &&
1250 opOperand, state,
true)) {
1251 op->emitOpError(
"not bufferizable under the given constraints: would "
1252 "write to read-only buffer");
1261 return success(!walkResult.wasInterrupted());
1271 if (isa<TensorType>(opOperand.get().getType()))
1281 auto buildAliasesArray = [&](
Value v) {
1283 state.applyOnAliases(v, [&](
Value alias) {
1285 llvm::raw_string_ostream stream(buffer);
1296 if (llvm::isa<TensorType>(opResult.getType())) {
1297 opResultAliasSets.push_back(buildAliasesArray(opResult));
1300 if (!opResultAliasSets.empty())
1305 bool hasTensorBbArg =
false;
1308 for (
Block &block : r.getBlocks()) {
1311 if (llvm::isa<TensorType>(bbArg.getType())) {
1312 bbArgAliasSets.push_back(buildAliasesArray(bbArg));
1313 hasTensorBbArg =
true;
1316 blockAliasSets.push_back(b.
getArrayAttr(bbArgAliasSets));
1318 regionAliasSets.push_back(b.
getArrayAttr(blockAliasSets));
1335 if (failed(state.analyzeOp(op, domInfo)))
1343 bool failedAnalysis =
false;
1346 state.gatherUndefinedTensorUses(op);
1352 if (BufferizableOpInterface bufferizableOp =
1353 options.dynCastBufferizableOp(op))
1354 failedAnalysis |= failed(bufferizableOp.verifyAnalysis(state));
1363 return success(!failedAnalysis);
1372 "invalid combination of bufferization flags");
1374 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.