57 #include "llvm/ADT/DenseSet.h" 
   58 #include "llvm/ADT/SetVector.h" 
   59 #include "llvm/Support/DebugLog.h" 
   65 #define DEBUG_TYPE "one-shot-analysis" 
   84     "__opresult_alias_set_attr__";
 
   94         cast<ArrayAttr>(attr).getAsValueRange<StringAttr>()));
 
   98       if (isa<TensorType>(opOperand.
get().
getType()))
 
  103               OpBuilder(op).getStrArrayAttr(inPlaceVector));
 
  116       if (isa<TensorType>(v.getType()))
 
  119       for (
Block &b : r.getBlocks())
 
  120         for (
auto bbArg : b.getArguments())
 
  121           if (isa<TensorType>(bbArg.getType()))
 
  126   op->
walk([&](BufferizableOpInterface bufferizableOp) {
 
  129     for (
OpOperand &opOperand : bufferizableOp->getOpOperands())
 
  130       if (isa<TensorType>(opOperand.get().getType()))
 
  131         if (bufferizableOp.mustBufferizeInPlace(opOperand, *
this))
 
  139   auto leaderIt = equivalentInfo.findLeader(v);
 
  140   for (
auto mit = leaderIt, meit = equivalentInfo.member_end(); mit != meit;
 
  148   auto leaderIt = aliasInfo.findLeader(v);
 
  149   for (
auto mit = leaderIt, meit = aliasInfo.member_end(); mit != meit; ++mit) {
 
  156   return equivalentInfo.isEquivalent(v1, v2);
 
  161   return aliasInfo.isEquivalent(v1, v2);
 
  165   if (inplaceBufferized.contains(&operand))
 
  167   inplaceBufferized.insert(&operand);
 
  169     aliasInfo.unionSets(alias.value, operand.
get());
 
  170   ++statNumTensorInPlace;
 
  174   assert(!inplaceBufferized.contains(&operand) &&
 
  175          "OpOperand was already decided to bufferize inplace");
 
  176   ++statNumTensorOutOfPlace;
 
  181   equivalentInfo.insert(v);
 
  193       if (!isa<TensorType>(opResult.getType()))
 
  198       if (opResult.getUses().empty())
 
  202       OpOperand *opOperand = &(*opResult.getUses().begin());
 
  204         for (
OpOperand &use : opResult.getUses())
 
  205           undefinedTensorUses.insert(&use);
 
  213   return undefinedTensorUses.contains(opOperand);
 
  217   return inplaceBufferized.contains(&opOperand);
 
  221   bool isWritten = 
false;
 
  233   if (
auto bufferizableOp =
 
  235     return bufferizableOp.isWritable(value, *
this);
 
  242   aliasInfo.unionSets(v1, v2);
 
  246   equivalentInfo.unionSets(v1, v2);
 
  259   if (!state.bufferizesToMemoryWrite(opOperand))
 
  262   return state.isInPlace(opOperand);
 
  359   for (
Value def : definitions) {
 
  362     Region *rDef = state.getEnclosingRepetitiveRegion(def, 
options);
 
  373       if (nextRegion == rDef)
 
  375       assert(nextRegion && 
"expected to find another repetitive region");
 
  413   for (
Value def : definitions) {
 
  414     Block *defBlock = def.getParentBlock();
 
  415     if (readBlock->
isReachable(writeBlock, {defBlock}) &&
 
  433   static uint64_t counter = 0;
 
  438   std::string 
id = 
"C_" + std::to_string(counter++);
 
  440   std::string conflictingWriteAttr =
 
  446   std::string readAttr =
 
  450   if (
auto opResult = dyn_cast<OpResult>(definition)) {
 
  451     std::string defAttr =
 
  452         id + 
"[DEF: result " + std::to_string(opResult.getResultNumber()) + 
"]";
 
  453     opResult.getDefiningOp()->setAttr(defAttr, b.
getUnitAttr());
 
  455     auto bbArg = cast<BlockArgument>(definition);
 
  456     std::string defAttr =
 
  457         id + 
"[DEF: bbArg " + std::to_string(bbArg.getArgNumber()) + 
"]";
 
  458     bbArg.getOwner()->getParentOp()->setAttr(defAttr, b.
getUnitAttr());
 
  474   config.followEquivalentOnly = 
true;
 
  475   config.alwaysIncludeLeaves = 
false;
 
  476   config.followSameTypeOrCastsOnly = 
true;
 
  478               .findValueInReverseUseDefChain(
 
  479                   start, [&](
Value v) { 
return v == other; }, 
config)
 
  487                                      SubsetInsertionOpInterface subsetOp) {
 
  488   auto matchingSubset = [&](
Value val) {
 
  489     if (
auto opResult = dyn_cast<OpResult>(val))
 
  490       if (subsetOp.isEquivalentSubset(opResult, [&](
Value v1, 
Value v2) {
 
  491             return state.areEquivalentBufferizedValues(v1, v2);
 
  499       state.findValueInReverseUseDefChain(opOperand, matchingSubset);
 
  500   return static_cast<bool>(llvm::all_of(backwardSlice, matchingSubset));
 
  516   if (
auto subsetOp = dyn_cast<SubsetInsertionOpInterface>(readingOp)) {
 
  524     if (uRead == &subsetOp.getDestinationOperand() &&
 
  540     if (uRead == &subsetOp.getSourceOperand() &&
 
  541         uConflictingWrite == &subsetOp.getDestinationOperand() &&
 
  556           dyn_cast<SubsetInsertionOpInterface>(conflictingWritingOp))
 
  573     if (uConflictingWrite == &subsetOp.getDestinationOperand() &&
 
  574         state.areEquivalentBufferizedValues(
 
  575             uRead->
get(), subsetOp.getSourceOperand().get()) &&
 
  599   if (
options.checkParallelRegions && !usesRead.empty()) {
 
  600     for (
OpOperand *uConflictingWrite : usesWrite) {
 
  608           state.findValueInReverseUseDefChain(uConflictingWrite, [&](
Value v) {
 
  609             return state.bufferizesToMemoryWrite(v);
 
  611       assert(!definitionsOrLeaves.empty() &&
 
  612              "expected at least one definition or leaf");
 
  616       for (
Value def : definitionsOrLeaves) {
 
  620           LDBG() << 
"\n- bufferizes out-of-place due to parallel region:\n" 
  621                  << 
"  unConflictingWrite = operand " 
  622                  << uConflictingWrite->getOperandNumber() << 
" of " 
  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";
 
  786             aliases.
getAliases()[0].value == definition) {
 
  787           LDBG() << 
"    no conflict: definition and write are same";
 
  795         LDBG() << 
"  => RaW CONFLICT FOUND";
 
  807   state.applyOnAliases(root, [&](
Value alias) {
 
  808     for (
auto &use : alias.
getUses())
 
  818   state.applyOnAliases(root, [&](
Value alias) {
 
  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);
 
  900   static int64_t counter = 0;
 
  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);
 
  930     foundWrite = !usesWrite.empty();
 
  937   bool foundReadOnly = 
false;
 
  938   auto checkReadOnly = [&](
Value v) {
 
  939     if (!state.isWritable(v)) {
 
  940       foundReadOnly = 
true;
 
  941       if (state.getOptions().printConflicts)
 
  945   state.applyOnAliases(operand.
get(), checkReadOnly);
 
  947     state.applyOnAliases(alias.value, checkReadOnly);
 
  949     LDBG() << 
"=> NOT WRITABLE";
 
  962 OneShotAnalysisState::findDefinitionsCached(
OpOperand *opOperand) {
 
  964   if (!cachedDefinitions.count(value))
 
  966   return cachedDefinitions[value];
 
  971   cachedDefinitions.clear();
 
  978   LDBG() << 
"//===-------------------------------------------===//\n" 
  982   bool foundInterference =
 
  986   if (foundInterference)
 
  987     state.bufferizeOutOfPlace(operand);
 
  989     state.bufferizeInPlace(operand);
 
  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()))
 
 1018         Value firstOperand = aliases.
begin()->opOperand->get();
 
 1019         bool allEquivalent = 
true;
 
 1022           bool isInPlace = state.isInPlace(*alias.opOperand);
 
 1023           Value operand = alias.opOperand->get();
 
 1024           if (isEquiv && isInPlace && alias.isDefinite) {
 
 1027             state.unionEquivalenceClasses(opResult, operand);
 
 1028             allEquivalent = 
false;
 
 1031           if (!isEquiv || !isInPlace)
 
 1032             allEquivalent = 
false;
 
 1033           if (!state.areEquivalentBufferizedValues(operand, firstOperand))
 
 1034             allEquivalent = 
false;
 
 1047         if (allEquivalent && !bufferizableOp.bufferizesToAllocation(opResult))
 
 1048           state.unionEquivalenceClasses(opResult, firstOperand);
 
 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))
 
 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);
 
 1114       result.push_back(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");
 
 1173 static LogicalResult
 
 1181   WalkResult walkResult = op->
walk([&](BufferizableOpInterface op) {
 
 1183     if (!
options.isOpAllowed(op.getOperation()))
 
 1187     if (!op.supportsUnstructuredControlFlow()) {
 
 1188       for (Region &r : op->getRegions()) {
 
 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");
 
 1193           return WalkResult::interrupt();
 
 1200   if (walkResult.wasInterrupted())
 
 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");
 
 1219     for (
OpOperand &opOperand : op->getOpOperands()) {
 
 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");
 
 1234         if (state.isInPlace(opOperand) &&
 
 1236                 opOperand, state, 
true)) {
 
 1237           op->emitOpError(
"not bufferizable under the given constraints: would " 
 1238                           "write to read-only buffer");
 
 1247   return success(!walkResult.wasInterrupted());
 
 1257       if (isa<TensorType>(opOperand.get().getType()))
 
 1267   auto buildAliasesArray = [&](
Value v) {
 
 1269     state.applyOnAliases(v, [&](
Value alias) {
 
 1271       llvm::raw_string_ostream stream(buffer);
 
 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;
 
 1332   state.gatherUndefinedTensorUses(op);
 
 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.
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.
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.
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.