58 #include "llvm/ADT/DenseSet.h"
59 #include "llvm/ADT/SetVector.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()))
199 for (
OpOperand &use : opResult.getUses())
200 undefinedTensorUses.insert(&use);
208 return undefinedTensorUses.contains(opOperand);
212 return inplaceBufferized.contains(&opOperand);
216 bool isWritten =
false;
228 if (
auto bufferizableOp =
230 return bufferizableOp.isWritable(value, *
this);
237 aliasInfo.unionSets(v1, v2);
241 equivalentInfo.unionSets(v1, v2);
254 if (!state.bufferizesToMemoryWrite(opOperand))
257 return state.isInPlace(opOperand);
279 worklist.push_back(succ);
280 while (!worklist.empty()) {
281 Block *next = worklist.pop_back_val();
282 if (llvm::find(except, next) != except.end())
286 if (visited.contains(next))
288 visited.insert(next);
290 worklist.push_back(succ);
374 for (
Value def : definitions) {
377 Region *rDef = state.getEnclosingRepetitiveRegion(def,
options);
388 if (nextRegion == rDef)
390 assert(nextRegion &&
"expected to find another repetitive region");
428 for (
Value def : definitions) {
429 Block *defBlock = def.getParentBlock();
430 if (
isReachable(readBlock, writeBlock, {defBlock}) &&
448 static uint64_t counter = 0;
453 std::string
id =
"C_" + std::to_string(counter++);
455 std::string conflictingWriteAttr =
461 std::string readAttr =
465 if (
auto opResult = dyn_cast<OpResult>(definition)) {
466 std::string defAttr =
467 id +
"[DEF: result " + std::to_string(opResult.getResultNumber()) +
"]";
468 opResult.getDefiningOp()->setAttr(defAttr, b.
getUnitAttr());
470 auto bbArg = cast<BlockArgument>(definition);
471 std::string defAttr =
472 id +
"[DEF: bbArg " + std::to_string(bbArg.getArgNumber()) +
"]";
473 bbArg.getOwner()->getParentOp()->setAttr(defAttr, b.
getUnitAttr());
492 .findValueInReverseUseDefChain(
493 start, [&](
Value v) {
return v == other; }, config)
500 SubsetInsertionOpInterface subsetOp) {
501 auto matchingSubset = [&](
Value val) {
502 if (
auto opResult = dyn_cast<OpResult>(val))
503 if (subsetOp.isEquivalentSubset(opResult, [&](
Value v1,
Value v2) {
504 return state.areEquivalentBufferizedValues(v1, v2);
512 state.findValueInReverseUseDefChain(value, matchingSubset);
513 return static_cast<bool>(llvm::all_of(backwardSlice, matchingSubset));
529 if (
auto subsetOp = dyn_cast<SubsetInsertionOpInterface>(readingOp)) {
537 if (uRead == &subsetOp.getDestinationOperand() &&
553 if (uRead == &subsetOp.getSourceOperand() &&
554 uConflictingWrite == &subsetOp.getDestinationOperand() &&
569 dyn_cast<SubsetInsertionOpInterface>(conflictingWritingOp))
586 if (uConflictingWrite == &subsetOp.getDestinationOperand() &&
587 state.areEquivalentBufferizedValues(
588 uRead->
get(), subsetOp.getSourceOperand().get()) &&
613 if (!usesRead.empty()) {
614 for (
OpOperand *uConflictingWrite : usesWrite) {
622 state.findValueInReverseUseDefChain(
623 uConflictingWrite->get(),
624 [&](
Value v) { return state.bufferizesToMemoryWrite(v); });
625 assert(!definitionsOrLeaves.empty() &&
626 "expected at least one definition or leaf");
630 for (
Value def : definitionsOrLeaves) {
636 <<
"\n- bufferizes out-of-place due to parallel region:\n");
637 LLVM_DEBUG(llvm::dbgs()
638 <<
" unConflictingWrite = operand "
639 << uConflictingWrite->getOperandNumber() <<
" of "
640 << *uConflictingWrite->getOwner() <<
"\n");
648 Operation *readingOp = uRead->getOwner();
649 LLVM_DEBUG(llvm::dbgs() <<
"\n- check conflict:\n");
650 LLVM_DEBUG(llvm::dbgs() <<
" uRead = operand " << uRead->getOperandNumber()
651 <<
" of " << *readingOp <<
"\n");
664 state.findDefinitionsCached(uRead->get());
665 if (definitions.empty()) {
667 LLVM_DEBUG(llvm::dbgs()
668 <<
" no conflict: read value has no definitions\n");
674 for (
OpOperand *uConflictingWrite : usesWrite) {
675 LLVM_DEBUG(llvm::dbgs() <<
" unConflictingWrite = operand "
676 << uConflictingWrite->getOperandNumber() <<
" of "
677 << *uConflictingWrite->getOwner() <<
"\n");
683 LLVM_DEBUG(llvm::dbgs() <<
"\n- useDominance = " << useDominance <<
"\n");
687 Operation *conflictingWritingOp = uConflictingWrite->getOwner();
698 if (
happensBefore(readingOp, conflictingWritingOp, domInfo)) {
699 LLVM_DEBUG(llvm::dbgs()
700 <<
" no conflict: read happens before write\n");
711 if (uConflictingWrite == uRead) {
712 LLVM_DEBUG(llvm::dbgs()
713 <<
" no conflict: read and write are same use\n");
723 LLVM_DEBUG(llvm::dbgs() <<
" no conflict: read and write are in "
724 "mutually exclusive regions\n");
732 if (conflictingWritingOp == readingOp) {
733 if (
auto bufferizableOp =
options.dynCastBufferizableOp(readingOp)) {
734 if (bufferizableOp.bufferizesToElementwiseAccess(
735 state, {uRead, uConflictingWrite})) {
737 state, uRead->get(), uConflictingWrite->get()) ||
739 state, uConflictingWrite->get(), uRead->get())) {
742 <<
" no conflict: op bufferizes to element-wise access\n");
751 LLVM_DEBUG(llvm::dbgs() <<
" no conflict: non-conflicting subsets\n");
756 if (
auto bufferizableOp =
options.dynCastBufferizableOp(readingOp)) {
757 if (bufferizableOp.isNotConflicting(uRead, uConflictingWrite, state)) {
758 LLVM_DEBUG(llvm::dbgs()
759 <<
" no conflict: op interace of reading op says 'no'\n");
764 if (conflictingWritingOp != readingOp) {
765 if (
auto bufferizableOp =
766 options.dynCastBufferizableOp(conflictingWritingOp)) {
767 if (bufferizableOp.isNotConflicting(uRead, uConflictingWrite,
771 <<
" no conflict: op interace of writing op says 'no'\n");
778 for (
Value definition : definitions) {
779 LLVM_DEBUG(llvm::dbgs() <<
" * definition = " << definition <<
"\n");
782 if (
Operation *defOp = definition.getDefiningOp()) {
785 LLVM_DEBUG(llvm::dbgs()
786 <<
" no conflict: write happens before definition\n");
790 if (defOp->isProperAncestor(conflictingWritingOp)) {
793 <<
" no conflict: write is contained in definition\n");
797 auto bbArg = cast<BlockArgument>(definition);
798 Block *block = bbArg.getOwner();
800 LLVM_DEBUG(llvm::dbgs() <<
" no conflict: definition is bbArg "
801 "and write happens outside of block\n");
812 aliases.
getAliases()[0].value == definition) {
813 LLVM_DEBUG(llvm::dbgs()
814 <<
" no conflict: definition and write are same\n");
822 LLVM_DEBUG(llvm::dbgs() <<
" => RaW CONFLICT FOUND\n");
834 state.applyOnAliases(root, [&](
Value alias) {
835 for (
auto &use : alias.
getUses())
845 state.applyOnAliases(root, [&](
Value alias) {
846 for (
auto &use : alias.
getUses()) {
848 if (state.bufferizesToMemoryRead(use)) {
868 if (!state.bufferizesToMemoryWrite(use)) {
869 AliasingValueList aliases = state.getAliasingValues(use);
870 if (llvm::any_of(aliases, [&](AliasingValue a) {
871 return state.isValueRead(a.value);
915 for (
AliasingValue alias : state.getAliasingValues(operand)) {
919 if (!checkConsistencyOnly && state.bufferizesToMemoryWrite(operand))
920 usesWrite.insert(&operand);
927 static int64_t counter = 0;
929 std::string
id =
"W_" + std::to_string(counter++);
930 if (
auto opResult = dyn_cast<OpResult>(value)) {
931 std::string attr =
id +
"[NOT-WRITABLE: result " +
932 std::to_string(opResult.getResultNumber()) +
"]";
933 opResult.getDefiningOp()->setAttr(attr, b.
getUnitAttr());
935 auto bbArg = cast<BlockArgument>(value);
936 std::string attr =
id +
"[NOT-WRITABLE: bbArg " +
937 std::to_string(bbArg.getArgNumber()) +
"]";
938 bbArg.getOwner()->getParentOp()->setAttr(attr, b.
getUnitAttr());
947 bool checkConsistencyOnly =
false) {
949 !checkConsistencyOnly && state.bufferizesToMemoryWrite(operand);
957 foundWrite = !usesWrite.empty();
964 bool foundReadOnly =
false;
965 auto checkReadOnly = [&](
Value v) {
966 if (!state.isWritable(v)) {
967 foundReadOnly =
true;
968 if (state.getOptions().printConflicts)
972 state.applyOnAliases(operand.
get(), checkReadOnly);
974 state.applyOnAliases(alias.value, checkReadOnly);
976 LLVM_DEBUG(llvm::dbgs() <<
"=> NOT WRITABLE\n");
989 OneShotAnalysisState::findDefinitionsCached(
Value value) {
990 if (!cachedDefinitions.count(value))
992 return cachedDefinitions[value];
997 cachedDefinitions.clear();
1005 llvm::dbgs() <<
"//===-------------------------------------------===//\n"
1007 <<
" of " << *operand.
getOwner() <<
"\n");
1009 bool foundInterference =
1013 if (foundInterference)
1014 state.bufferizeOutOfPlace(operand);
1016 state.bufferizeInPlace(operand);
1018 LLVM_DEBUG(llvm::dbgs()
1019 <<
"//===-------------------------------------------===//\n");
1027 if (isa<TensorType>(opOperand.get().getType()))
1037 return hasTensorResult || hasTensorOperand;
1044 if (
auto bufferizableOp = state.getOptions().dynCastBufferizableOp(op)) {
1046 if (!isa<TensorType>(opResult.getType()))
1053 Value firstOperand = aliases.
begin()->opOperand->get();
1054 bool allEquivalent =
true;
1057 bool isInPlace = state.isInPlace(*alias.opOperand);
1058 Value operand = alias.opOperand->get();
1059 if (isEquiv && isInPlace && alias.isDefinite) {
1062 state.unionEquivalenceClasses(opResult, operand);
1063 allEquivalent =
false;
1066 if (!isEquiv || !isInPlace)
1067 allEquivalent =
false;
1068 if (!state.areEquivalentBufferizedValues(operand, firstOperand))
1069 allEquivalent =
false;
1082 if (allEquivalent && !bufferizableOp.bufferizesToAllocation(opResult))
1083 state.unionEquivalenceClasses(opResult, firstOperand);
1119 std::mt19937 g(
getOptions().analysisFuzzerSeed);
1120 llvm::shuffle(ops.begin(), ops.end(), g);
1130 }
else if (heuristic ==
1136 llvm_unreachable(
"unsupported heuristic");
1153 WalkResult walkResult = op->
walk([&](BufferizableOpInterface op) {
1155 if (!
options.isOpAllowed(op.getOperation()))
1159 if (!op.supportsUnstructuredControlFlow()) {
1160 for (Region &r : op->getRegions()) {
1161 if (r.getBlocks().size() > 1) {
1162 op->emitOpError(
"op or BufferizableOpInterface implementation does "
1163 "not support unstructured control flow, but at least "
1164 "one region has multiple blocks");
1165 return WalkResult::interrupt();
1172 if (walkResult.wasInterrupted())
1175 walkResult = op->
walk([&](BufferizableOpInterface op) {
1177 if (!
options.isOpAllowed(op.getOperation()))
1183 if (
auto toTensorOp = dyn_cast<ToTensorOp>(op.getOperation())) {
1184 if (!toTensorOp.getRestrict() && !toTensorOp->getUses().empty()) {
1185 op->
emitOpError(
"to_tensor ops without `restrict` are not supported by "
1186 "One-Shot Analysis");
1192 if (isa<TensorType>(opOperand.get().getType())) {
1194 opOperand, domInfo, state,
1201 op->
emitOpError(
"not bufferizable under the given constraints: "
1202 "cannot avoid RaW conflict");
1206 if (state.isInPlace(opOperand) &&
1208 opOperand, state,
true)) {
1209 op->
emitOpError(
"not bufferizable under the given constraints: would "
1210 "write to read-only buffer");
1219 return success(!walkResult.wasInterrupted());
1229 if (isa<TensorType>(opOperand.get().getType()))
1239 auto buildAliasesArray = [&](
Value v) {
1241 state.applyOnAliases(v, [&](
Value alias) {
1243 llvm::raw_string_ostream stream(buffer);
1254 if (llvm::isa<TensorType>(opResult.getType())) {
1255 opResultAliasSets.push_back(buildAliasesArray(opResult));
1258 if (!opResultAliasSets.empty())
1263 bool hasTensorBbArg =
false;
1266 for (
Block &block : r.getBlocks()) {
1269 if (llvm::isa<TensorType>(bbArg.getType())) {
1270 bbArgAliasSets.push_back(buildAliasesArray(bbArg));
1271 hasTensorBbArg =
true;
1274 blockAliasSets.push_back(b.
getArrayAttr(bbArgAliasSets));
1276 regionAliasSets.push_back(b.
getArrayAttr(blockAliasSets));
1293 if (
failed(state.analyzeOp(op, domInfo)))
1301 bool failedAnalysis =
false;
1304 state.gatherUndefinedTensorUses(op);
1310 if (BufferizableOpInterface bufferizableOp =
1311 options.dynCastBufferizableOp(op))
1312 failedAnalysis |=
failed(bufferizableOp.verifyAnalysis(state));
1321 return success(!failedAnalysis);
1329 "invalid combination of bufferization flags");
1330 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 bool hasTensorSemantics(Operation *op)
Return true if the given op has a tensor result or a tensor operand.
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.
static bool isReachable(Block *from, Block *to, ArrayRef< Block * > except)
static bool matchesInsertDestination(const AnalysisState &state, Value value, SubsetInsertionOpInterface subsetOp)
Return "true" if value is originating from a subset that is equivalent to the subset that subsetOp in...
constexpr StringLiteral kOpResultAliasSetAttrName
static bool hasEquivalentValueInReverseUseDefChain(AnalysisState &state, Value 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 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 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 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 ...
SuccessorRange getSuccessors()
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.
operand_type_range getOperandTypes()
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.
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.
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(Value value) const
Find the values that may define the contents of the given value at runtime.
virtual void resetCache()
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(Value value)
Find the definitions of the given tensor 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 runOneShotBufferize(Operation *op, const OneShotBufferizationOptions &options, BufferizationStatistics *statistics=nullptr)
Run One-Shot Bufferize on the given op: Analysis + Bufferization.
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 bufferizeOp(Operation *op, const BufferizationOptions &options, BufferizationStatistics *statistics=nullptr)
Bufferize op and its nested ops that implement BufferizableOpInterface.
LogicalResult insertTensorCopies(Operation *op, const OneShotBufferizationOptions &options, BufferizationStatistics *statistics=nullptr)
Resolve RaW and other conflicts by inserting bufferization.alloc_tensor ops.
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.
Include the generated interface declarations.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
bool insideMutuallyExclusiveRegions(Operation *a, Operation *b)
Return true if a and b are in mutually exclusive regions as per RegionBranchOpInterface.
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value.
This class represents an efficient way to signal success or failure.
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.
Traversal parameters for findValueInReverseUseDefChain.
bool alwaysIncludeLeaves
Specifies if leaves (that do not have further OpOperands to follow) should be returned even if they d...
bool followSameTypeOrCastsOnly
Specifies whether OpOperands with a different type that are not the result of a CastOpInterface op sh...
bool followEquivalentOnly
Specifies whether non-equivalent OpOperands should be followed.