diff --git a/mlir/include/mlir/Dialect/Linalg/ComprehensiveBufferize/BufferizableOpInterface.h b/mlir/include/mlir/Dialect/Linalg/ComprehensiveBufferize/BufferizableOpInterface.h --- a/mlir/include/mlir/Dialect/Linalg/ComprehensiveBufferize/BufferizableOpInterface.h +++ b/mlir/include/mlir/Dialect/Linalg/ComprehensiveBufferize/BufferizableOpInterface.h @@ -13,6 +13,7 @@ #include "mlir/IR/BuiltinTypes.h" #include "mlir/IR/Operation.h" #include "mlir/Support/LLVM.h" +#include "llvm/ADT/EquivalenceClasses.h" namespace mlir { class BlockAndValueMapping; @@ -31,6 +32,105 @@ Equivalent }; +/// The BufferizationAliasInfo class maintains a list of buffer aliases and +/// equivalence classes to support bufferization. +class BufferizationAliasInfo { +public: + explicit BufferizationAliasInfo(Operation *rootOp); + + /// Add a new entry for `v` in the `aliasInfo` and `equivalentInfo`. In the + /// beginning the alias and equivalence sets only contain `v` itself. + void createAliasInfoEntry(Value v); + + /// Insert an info entry for `newValue` and merge its alias set with that of + /// `alias`. + void insertNewBufferAlias(Value newValue, Value alias); + + /// Insert an info entry for `newValue` and merge its alias set with that of + /// `alias`. Additionally, merge their equivalence classes. + void insertNewBufferEquivalence(Value newValue, Value alias); + + /// Set the inPlace bufferization spec to true. + /// Merge result's and operand's aliasing sets and iterate to a fixed point. + void bufferizeInPlace(OpResult result, OpOperand &operand); + + /// Set the inPlace bufferization spec to false. + void bufferizeOutOfPlace(OpResult result); + + /// Return true if `v1` and `v2` bufferize to equivalent buffers. + bool areEquivalentBufferizedValues(Value v1, Value v2) const { + return equivalentInfo.isEquivalent(v1, v2); + } + + /// Return true if `v1` and `v2` bufferize to aliasing buffers. + bool areAliasingBufferizedValues(Value v1, Value v2) const { + return aliasInfo.isEquivalent(v1, v2); + } + + /// Union the alias sets of `v1` and `v2`. + void unionAliasSets(Value v1, Value v2) { aliasInfo.unionSets(v1, v2); } + + /// Union the equivalence classes of `v1` and `v2`. + void unionEquivalenceClasses(Value v1, Value v2) { + equivalentInfo.unionSets(v1, v2); + } + + /// Apply `fun` to all the members of the equivalence class of `v`. + void applyOnEquivalenceClass(Value v, function_ref fun) const; + + /// Apply `fun` to all aliases of `v`. + void applyOnAliases(Value v, function_ref fun) const; + + // TODO: Move these out of BufferizationAliasInfo. + /// Return true if the value is known to bufferize to writable memory. + bool bufferizesToWritableMemory(Value v) const; + + /// Specify that the value is known to bufferize to writable memory. + void setBufferizesToWritableMemory(Value v); + + /// Mark a value as in-place bufferized. + void markInPlace(OpResult v) { inplaceBufferized.insert(v); } + + /// Return `true` if a value was marked as in-place bufferized. + bool isInPlace(OpResult opResult) const; + +private: + /// llvm::EquivalenceClasses wants comparable elements. This comparator uses + /// uses pointer comparison on the defining op. This is a poor man's + /// comparison but it's not like UnionFind needs ordering anyway. + struct ValueComparator { + bool operator()(const Value &lhs, const Value &rhs) const { + return lhs.getImpl() < rhs.getImpl(); + } + }; + + using EquivalenceClassRangeType = llvm::iterator_range< + llvm::EquivalenceClasses::member_iterator>; + /// Check that aliasInfo for `v` exists and return a reference to it. + EquivalenceClassRangeType getAliases(Value v) const; + + /// Set of tensors that are known to bufferize to writable memory. + llvm::DenseSet bufferizeToWritableMemory; + + /// Set of all OpResults that were decided to bufferize in-place. + llvm::DenseSet inplaceBufferized; + + /// Auxiliary structure to store all the values a given value may alias with. + /// Alias information is "may be" conservative: In the presence of branches, a + /// value may alias with one of multiple other values. The concrete aliasing + /// value may not even be known at compile time. All such values are + /// considered to be aliases. + llvm::EquivalenceClasses aliasInfo; + + /// Auxiliary structure to store all the equivalent buffer classes. Equivalent + /// buffer information is "must be" conservative: Only if two values are + /// guaranteed to be equivalent at runtime, they said to be equivalent. It is + /// possible that, in the presence of branches, it cannot be determined + /// statically if two values are equivalent. In that case, the values are + /// considered to be not equivalent. + llvm::EquivalenceClasses equivalentInfo; +}; + /// Determine which OpOperand* will alias with `result` if the op is bufferized /// in place. Return an empty vector if the op is not bufferizable. SmallVector getAliasingOpOperand(OpResult result); diff --git a/mlir/include/mlir/Dialect/Linalg/ComprehensiveBufferize/ComprehensiveBufferize.h b/mlir/include/mlir/Dialect/Linalg/ComprehensiveBufferize/ComprehensiveBufferize.h --- a/mlir/include/mlir/Dialect/Linalg/ComprehensiveBufferize/ComprehensiveBufferize.h +++ b/mlir/include/mlir/Dialect/Linalg/ComprehensiveBufferize/ComprehensiveBufferize.h @@ -11,7 +11,6 @@ #include "mlir/Dialect/Tensor/IR/Tensor.h" #include "mlir/IR/Value.h" -#include "llvm/ADT/EquivalenceClasses.h" #include "llvm/ADT/SetOperations.h" namespace mlir { @@ -24,124 +23,11 @@ namespace linalg { namespace comprehensive_bufferize { +class BufferizationAliasInfo; + // TODO: from some HW description. static constexpr int64_t kBufferAlignments = 128; -/// The BufferizationAliasInfo class maintains a list of buffer aliases and -/// equivalence classes to support bufferization. -/// ExtractSliceOps have special behavior, they act as a level of indirection -/// for bufferization. They don't create reads or writes themselves and analysis -/// needs to look through their uses. -/// ExtractSliceOp + InsertSliceOp have special joint behavior: they may -/// bufferize to the same buffer (i.e. subview), which is what introduces the -/// need for bufferization classes. -/// Some of these functionalities could be refactored in a Bufferizer class that -/// uses BufferizationAliasInfo. -class BufferizationAliasInfo { -public: - explicit BufferizationAliasInfo(Operation *rootOp); - - /// Add a new entry for `v` in the `aliasInfo` and `equivalentInfo`. In the - /// beginning the alias and equivalence sets only contain `v` itself. - void createAliasInfoEntry(Value v); - - /// Insert an info entry for `newValue` and merge its alias set with that of - /// `alias`. - void insertNewBufferAlias(Value newValue, Value alias); - - /// Insert an info entry for `newValue` and merge its alias set with that of - /// `alias`. Additionally, merge their equivalence classes. - void insertNewBufferEquivalence(Value newValue, Value alias); - - /// Set the inPlace bufferization spec to true. - /// Merge result's and operand's aliasing sets and iterate to a fixed point. - void bufferizeInPlace(OpResult result, OpOperand &operand); - - /// Set the inPlace bufferization spec to false. - void bufferizeOutOfPlace(OpResult result); - - /// Return true if `v1` and `v2` bufferize to equivalent buffers. - bool areEquivalentBufferizedValues(Value v1, Value v2) const { - return equivalentInfo.isEquivalent(v1, v2); - } - - /// Return true if `v1` and `v2` bufferize to aliasing buffers. - bool areAliasingBufferizedValues(Value v1, Value v2) const { - return aliasInfo.isEquivalent(v1, v2); - } - - /// Union the alias sets of `v1` and `v2`. - void unionAliasSets(Value v1, Value v2) { aliasInfo.unionSets(v1, v2); } - - /// Union the equivalence classes of `v1` and `v2`. - void unionEquivalenceClasses(Value v1, Value v2) { - equivalentInfo.unionSets(v1, v2); - } - - /// Apply `fun` to all the members of the equivalence class of `v`. - void applyOnEquivalenceClass(Value v, function_ref fun) const; - - /// Apply `fun` to all aliases of `v`. - void applyOnAliases(Value v, function_ref fun) const; - - // TODO: Move these out of BufferizationAliasInfo. - /// Return true if the value is known to bufferize to writable memory. - bool bufferizesToWritableMemory(Value v) const; - - /// Specify that the value is known to bufferize to writable memory. - void setBufferizesToWritableMemory(Value v); - - /// Mark a value as in-place bufferized. - void markInPlace(OpResult v) { inplaceBufferized.insert(v); } - - /// Return `true` if a value was marked as in-place bufferized. - bool isInPlace(OpResult opResult) const; - - /// Print to `os`. - void printAliases(raw_ostream &os) const; - void printEquivalences(raw_ostream &os) const; - - /// Print to `errs()`. - void dumpAliases() const; - void dumpEquivalences() const; - -private: - /// llvm::EquivalenceClasses wants comparable elements. This comparator uses - /// uses pointer comparison on the defining op. This is a poor man's - /// comparison but it's not like UnionFind needs ordering anyway. - struct ValueComparator { - bool operator()(const Value &lhs, const Value &rhs) const { - return lhs.getImpl() < rhs.getImpl(); - } - }; - - using EquivalenceClassRangeType = llvm::iterator_range< - llvm::EquivalenceClasses::member_iterator>; - /// Check that aliasInfo for `v` exists and return a reference to it. - EquivalenceClassRangeType getAliases(Value v) const; - - /// Set of tensors that are known to bufferize to writable memory. - llvm::DenseSet bufferizeToWritableMemory; - - /// Set of all OpResults that were decided to bufferize in-place. - llvm::DenseSet inplaceBufferized; - - /// Auxiliary structure to store all the values a given value may alias with. - /// Alias information is "may be" conservative: In the presence of branches, a - /// value may alias with one of multiple other values. The concrete aliasing - /// value may not even be known at compile time. All such values are - /// considered to be aliases. - llvm::EquivalenceClasses aliasInfo; - - /// Auxiliary structure to store all the equivalent buffer classes. Equivalent - /// buffer information is "must be" conservative: Only if two values are - /// guaranteed to be equivalent at runtime, they said to be equivalent. It is - /// possible that, in the presence of branches, it cannot be determined - /// statically if two values are equivalent. In that case, the values are - /// considered to be not equivalent. - llvm::EquivalenceClasses equivalentInfo; -}; - /// Analyze the `ops` to determine which OpResults are inplaceable. LogicalResult inPlaceAnalysis(SmallVector &ops, BufferizationAliasInfo &aliasInfo, diff --git a/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/BufferizableOpInterface.cpp b/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/BufferizableOpInterface.cpp --- a/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/BufferizableOpInterface.cpp +++ b/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/BufferizableOpInterface.cpp @@ -8,6 +8,7 @@ #include "mlir/Dialect/Linalg/ComprehensiveBufferize/BufferizableOpInterface.h" #include "mlir/IR/Operation.h" +#include "llvm/Support/Debug.h" namespace mlir { namespace linalg { @@ -19,9 +20,150 @@ } // namespace linalg } // namespace mlir +#define DEBUG_TYPE "bufferizable-op-interface" +#define DBGS() (llvm::dbgs() << '[' << DEBUG_TYPE << "] ") +#define LDBG(X) LLVM_DEBUG(DBGS() << X) + using namespace mlir; using namespace linalg::comprehensive_bufferize; +//===----------------------------------------------------------------------===// +// BufferizationAliasInfo +//===----------------------------------------------------------------------===// + +BufferizationAliasInfo::BufferizationAliasInfo(Operation *rootOp) { + rootOp->walk([&](Operation *op) { + for (Value v : op->getResults()) + if (v.getType().isa()) + createAliasInfoEntry(v); + for (Region &r : op->getRegions()) + for (Block &b : r.getBlocks()) + for (auto bbArg : b.getArguments()) + if (bbArg.getType().isa()) + createAliasInfoEntry(bbArg); + }); + + // Set up alias sets for OpResults that must bufferize in-place. This should + // be done before making any other bufferization decisions. + rootOp->walk([&](BufferizableOpInterface bufferizableOp) { + for (OpResult opResult : bufferizableOp->getOpResults()) { + if (opResult.getType().isa()) + if (bufferizableOp.mustBufferizeInPlace(opResult)) { + SmallVector operands = + bufferizableOp.getAliasingOpOperand(opResult); + assert(!operands.empty() && + "expected that OpResult has aliasing OpOperand"); + for (OpOperand *operand : operands) + aliasInfo.unionSets(operand->get(), opResult); + markInPlace(opResult); + } + } + }); +} + +/// Add a new entry for `v` in the `aliasInfo` and `equivalentInfo`. In the +/// beginning the alias and equivalence sets only contain `v` itself. +void BufferizationAliasInfo::createAliasInfoEntry(Value v) { + aliasInfo.insert(v); + equivalentInfo.insert(v); +} + +/// Insert an info entry for `newValue` and merge its alias set with that of +/// `alias`. +void BufferizationAliasInfo::insertNewBufferAlias(Value newValue, Value alias) { + createAliasInfoEntry(newValue); + aliasInfo.unionSets(newValue, alias); +} + +/// Insert an info entry for `newValue` and merge its alias set with that of +/// `alias`. Additionally, merge their equivalence classes. +void BufferizationAliasInfo::insertNewBufferEquivalence(Value newValue, + Value alias) { + insertNewBufferAlias(newValue, alias); + equivalentInfo.unionSets(newValue, alias); +} + +bool BufferizationAliasInfo::bufferizesToWritableMemory(Value v) const { + return bufferizeToWritableMemory.count(v) > 0; +} + +/// Specify that the value is known to bufferize to writable memory. +void BufferizationAliasInfo::setBufferizesToWritableMemory(Value v) { + bufferizeToWritableMemory.insert(v); +} + +/// Return `true` if a value was marked as in-place bufferized. +bool BufferizationAliasInfo::isInPlace(OpResult opResult) const { + bool inplace = inplaceBufferized.contains(opResult); +#ifndef NDEBUG + if (inplace) { + auto bufferizableOp = + dyn_cast(opResult.getDefiningOp()); + assert(bufferizableOp && + "expected that in-place bufferized op is bufferizable"); + SmallVector operands = + bufferizableOp.getAliasingOpOperand(opResult); + for (OpOperand *operand : operands) + assert(areAliasingBufferizedValues(operand->get(), opResult) && + "expected that in-place bufferized OpResult aliases with " + "aliasing OpOperand"); + } +#endif // NDEBUG + return inplace; +} + +/// Set the inPlace bufferization spec to true. +void BufferizationAliasInfo::bufferizeInPlace(OpResult result, + OpOperand &operand) { + LLVM_DEBUG(llvm::dbgs() << "bufferizeInPlace: "); + LLVM_DEBUG(result.print(llvm::dbgs())); + + markInPlace(result); + aliasInfo.unionSets(result, operand.get()); + if (bufferRelation(operand) == BufferRelation::Equivalent) + equivalentInfo.unionSets(result, operand.get()); +} + +/// Set the inPlace bufferization spec to false. +void BufferizationAliasInfo::bufferizeOutOfPlace(OpResult result) { + LLVM_DEBUG(llvm::dbgs() << "bufferizeOutOfPlace: "); + LLVM_DEBUG(result.print(llvm::dbgs())); + + if (inplaceBufferized.contains(result)) + inplaceBufferized.erase(result); +} + +/// Apply `fun` to all the members of the equivalence class of `v`. +void BufferizationAliasInfo::applyOnEquivalenceClass( + Value v, function_ref fun) const { + auto leaderIt = equivalentInfo.findLeader(v); + for (auto mit = leaderIt, meit = equivalentInfo.member_end(); mit != meit; + ++mit) { + fun(*mit); + } +} + +/// Apply `fun` to all aliases of `v`. +void BufferizationAliasInfo::applyOnAliases( + Value v, function_ref fun) const { + auto leaderIt = aliasInfo.findLeader(v); + for (auto mit = leaderIt, meit = aliasInfo.member_end(); mit != meit; ++mit) { + fun(*mit); + } +} + +BufferizationAliasInfo::EquivalenceClassRangeType +BufferizationAliasInfo::getAliases(Value v) const { + DenseSet res; + auto it = aliasInfo.findValue(aliasInfo.getLeaderValue(v)); + for (auto mit = aliasInfo.member_begin(it), meit = aliasInfo.member_end(); + mit != meit; ++mit) { + res.insert(static_cast(*mit)); + } + return BufferizationAliasInfo::EquivalenceClassRangeType( + aliasInfo.member_begin(it), aliasInfo.member_end()); +} + //===----------------------------------------------------------------------===// // Helper functions for BufferizableOpInterface //===----------------------------------------------------------------------===// diff --git a/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/ComprehensiveBufferize.cpp b/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/ComprehensiveBufferize.cpp --- a/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/ComprehensiveBufferize.cpp +++ b/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/ComprehensiveBufferize.cpp @@ -351,58 +351,6 @@ return opResult && aliasInfo.isInPlace(opResult); } -BufferizationAliasInfo::BufferizationAliasInfo(Operation *rootOp) { - rootOp->walk([&](Operation *op) { - for (Value v : op->getResults()) - if (v.getType().isa()) - createAliasInfoEntry(v); - for (Region &r : op->getRegions()) - for (Block &b : r.getBlocks()) - for (auto bbArg : b.getArguments()) - if (bbArg.getType().isa()) - createAliasInfoEntry(bbArg); - }); - - // Set up alias sets for OpResults that must bufferize in-place. This should - // be done before making any other bufferization decisions. - rootOp->walk([&](BufferizableOpInterface bufferizableOp) { - for (OpResult opResult : bufferizableOp->getOpResults()) { - if (opResult.getType().isa()) - if (bufferizableOp.mustBufferizeInPlace(opResult)) { - SmallVector operands = - bufferizableOp.getAliasingOpOperand(opResult); - assert(!operands.empty() && - "expected that OpResult has aliasing OpOperand"); - for (OpOperand *operand : operands) - aliasInfo.unionSets(operand->get(), opResult); - markInPlace(opResult); - } - } - }); -} - -/// Add a new entry for `v` in the `aliasInfo` and `equivalentInfo`. In the -/// beginning the alias and equivalence sets only contain `v` itself. -void BufferizationAliasInfo::createAliasInfoEntry(Value v) { - aliasInfo.insert(v); - equivalentInfo.insert(v); -} - -/// Insert an info entry for `newValue` and merge its alias set with that of -/// `alias`. -void BufferizationAliasInfo::insertNewBufferAlias(Value newValue, Value alias) { - createAliasInfoEntry(newValue); - aliasInfo.unionSets(newValue, alias); -} - -/// Insert an info entry for `newValue` and merge its alias set with that of -/// `alias`. Additionally, merge their equivalence classes. -void BufferizationAliasInfo::insertNewBufferEquivalence(Value newValue, - Value alias) { - insertNewBufferAlias(newValue, alias); - equivalentInfo.unionSets(newValue, alias); -} - /// Return true if, under current bufferization decisions, the buffer of `value` /// is not writable. static bool aliasesNonWritableBuffer(Value value, @@ -438,15 +386,6 @@ return foundNonWritableBuffer; } -bool BufferizationAliasInfo::bufferizesToWritableMemory(Value v) const { - return bufferizeToWritableMemory.count(v) > 0; -} - -/// Specify that the value is known to bufferize to writable memory. -void BufferizationAliasInfo::setBufferizesToWritableMemory(Value v) { - bufferizeToWritableMemory.insert(v); -} - /// Return true if the buffer to which `operand` would bufferize is equivalent /// to some buffer write. static bool aliasesInPlaceWrite(Value value, @@ -471,45 +410,6 @@ return foundInplaceWrite; } -/// Return `true` if a value was marked as in-place bufferized. -bool BufferizationAliasInfo::isInPlace(OpResult opResult) const { - bool inplace = inplaceBufferized.contains(opResult); -#ifndef NDEBUG - if (inplace) { - auto bufferizableOp = - dyn_cast(opResult.getDefiningOp()); - assert(bufferizableOp && - "expected that in-place bufferized op is bufferizable"); - SmallVector operands = - bufferizableOp.getAliasingOpOperand(opResult); - for (OpOperand *operand : operands) - assert(areAliasingBufferizedValues(operand->get(), opResult) && - "expected that in-place bufferized OpResult aliases with " - "aliasing OpOperand"); - } -#endif // NDEBUG - return inplace; -} - -/// Set the inPlace bufferization spec to true. -void BufferizationAliasInfo::bufferizeInPlace(OpResult result, - OpOperand &operand) { - markInPlace(result); - aliasInfo.unionSets(result, operand.get()); - // Dump the updated alias analysis. - LLVM_DEBUG(dumpAliases()); - if (bufferRelation(operand) == BufferRelation::Equivalent) - equivalentInfo.unionSets(result, operand.get()); - // Dump the updated equivalence analysis. - LLVM_DEBUG(dumpEquivalences()); -} - -/// Set the inPlace bufferization spec to false. -void BufferizationAliasInfo::bufferizeOutOfPlace(OpResult result) { - if (inplaceBufferized.contains(result)) - inplaceBufferized.erase(result); -} - /// Starting from `value`, follow the use-def chain in reverse, always selecting /// the aliasing OpOperands. Find and return Values for which `condition` /// evaluates to true. OpOperands of such matching Values are not traversed any @@ -840,81 +740,6 @@ return true; } -/// Apply `fun` to all the members of the equivalence class of `v`. -void BufferizationAliasInfo::applyOnEquivalenceClass( - Value v, function_ref fun) const { - auto leaderIt = equivalentInfo.findLeader(v); - for (auto mit = leaderIt, meit = equivalentInfo.member_end(); mit != meit; - ++mit) { - fun(*mit); - } -} - -/// Apply `fun` to all aliases of `v`. -void BufferizationAliasInfo::applyOnAliases( - Value v, function_ref fun) const { - auto leaderIt = aliasInfo.findLeader(v); - for (auto mit = leaderIt, meit = aliasInfo.member_end(); mit != meit; ++mit) { - fun(*mit); - } -} - -void BufferizationAliasInfo::printAliases(raw_ostream &os) const { - os << "\n/===================== AliasInfo =====================\n"; - for (auto it = aliasInfo.begin(), eit = aliasInfo.end(); it != eit; ++it) { - if (!it->isLeader()) - continue; - Value leader = it->getData(); - os << "|\n| -- leader: " << printValueInfo(leader, /*prefix=*/false) - << '\n'; - for (auto mit = aliasInfo.member_begin(it), meit = aliasInfo.member_end(); - mit != meit; ++mit) { - Value v = static_cast(*mit); - os << "| ---- aliasing member: " << printValueInfo(v, /*prefix=*/false) - << '\n'; - } - } - os << "\n/===================== End AliasInfo =====================\n\n"; -} - -void BufferizationAliasInfo::printEquivalences(raw_ostream &os) const { - os << "\n/********************* Equivalent Buffers *********************\n"; - for (auto it = equivalentInfo.begin(), eit = equivalentInfo.end(); it != eit; - ++it) { - if (!it->isLeader()) - continue; - Value leader = it->getData(); - os << "|\n| -- leader: " << printValueInfo(leader, /*prefix=*/false) - << '\n'; - for (auto mit = equivalentInfo.member_begin(it), - meit = equivalentInfo.member_end(); - mit != meit; ++mit) { - Value v = static_cast(*mit); - os << "| ---- equivalent member: " << printValueInfo(v, /*prefix=*/false) - << '\n'; - } - } - os << "|\n\\***************** End Equivalent Buffers *****************\n\n"; -} - -BufferizationAliasInfo::EquivalenceClassRangeType -BufferizationAliasInfo::getAliases(Value v) const { - DenseSet res; - auto it = aliasInfo.findValue(aliasInfo.getLeaderValue(v)); - for (auto mit = aliasInfo.member_begin(it), meit = aliasInfo.member_end(); - mit != meit; ++mit) { - res.insert(static_cast(*mit)); - } - return BufferizationAliasInfo::EquivalenceClassRangeType( - aliasInfo.member_begin(it), aliasInfo.member_end()); -} - -void BufferizationAliasInfo::dumpAliases() const { printAliases(llvm::errs()); } - -void BufferizationAliasInfo::dumpEquivalences() const { - printEquivalences(llvm::errs()); -} - //===----------------------------------------------------------------------===// // Forward declarations. //===----------------------------------------------------------------------===//