diff --git a/include/mlir/Analysis/Liveness.h b/include/mlir/Analysis/Liveness.h index 2df2bdafbb8f..a2f67b607f69 100644 --- a/include/mlir/Analysis/Liveness.h +++ b/include/mlir/Analysis/Liveness.h @@ -26,18 +26,18 @@ #ifndef MLIR_ANALYSIS_LIVENESS_H #define MLIR_ANALYSIS_LIVENESS_H -#include +#include "mlir/Support/LLVM.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/SmallPtrSet.h" +#include namespace mlir { class Block; +class LivenessBlockInfo; +class Operation; class Region; class Value; -class Operation; - -class LivenessBlockInfo; /// Represents an analysis for computing liveness information from a /// given top-level operation. The analysis iterates over all associated @@ -46,16 +46,16 @@ class LivenessBlockInfo; /// included in the mentioned regions. It relies on a fixpoint iteration /// to compute all live-in and live-out values of all included blocks. /// Sample usage: -/// Liveness liveness(topLevelOp); -/// auto &allInValues = liveness.getLiveIn(block); -/// auto &allOutValues = liveness.getLiveOut(block); -/// auto allOperationsInWhichValueIsLive = liveness.resolveLiveness(value); -/// bool lastUse = liveness.isLastUse(value, operation); +/// Liveness liveness(topLevelOp); +/// auto &allInValues = liveness.getLiveIn(block); +/// auto &allOutValues = liveness.getLiveOut(block); +/// auto allOperationsInWhichValueIsLive = liveness.resolveLiveness(value); +/// bool lastUse = liveness.isLastUse(value, operation); class Liveness { public: using OperationListT = std::vector; - using BlockMapT = llvm::DenseMap; - using ValueSetT = llvm::SmallDenseSet; + using BlockMapT = DenseMap; + using ValueSetT = SmallPtrSet; public: /// Creates a new Liveness analysis that computes liveness @@ -67,7 +67,9 @@ class Liveness { /// Gets liveness info (if any) for the given value. /// This includes all operations in which the given value is live. - /// Note that the operations in this list are not ordered. + /// Note that the operations in this list are not ordered and the current + /// implementation is computationally expensive (as it iterates over all + /// blocks in which the given value is live). OperationListT resolveLiveness(Value *value) const; /// Gets liveness info (if any) for the block. @@ -87,11 +89,11 @@ class Liveness { void dump() const; /// Dumps the liveness information to the given stream. - void print(llvm::raw_ostream &os) const; + void print(raw_ostream &os) const; private: /// Initializes the internal mappings. - void build(llvm::MutableArrayRef regions); + void build(MutableArrayRef regions); private: /// The operation this analysis was constructed from. @@ -125,8 +127,10 @@ class LivenessBlockInfo { /// Returns true if the given value is in the live-out set. bool isLiveOut(Value *value) const; - /// Gets the start operation for the given value - /// (must be referenced in this block). + /// Gets the start operation for the given value. This is the first operation + /// the given value is considered to be live. This could either be the start + /// operation of the current block (in case the value is live-in) or the + /// operation that defines the given value (must be referenced in this block). Operation *getStartOperation(Value *value) const; /// Gets the end operation for the given value using the start operation diff --git a/lib/Analysis/Liveness.cpp b/lib/Analysis/Liveness.cpp index 73992ca14648..c7e626554ee3 100644 --- a/lib/Analysis/Liveness.cpp +++ b/lib/Analysis/Liveness.cpp @@ -24,6 +24,7 @@ #include "mlir/IR/Operation.h" #include "mlir/IR/Region.h" #include "mlir/IR/Value.h" +#include "llvm/ADT/SetOperations.h" #include "llvm/ADT/SetVector.h" #include "llvm/Support/raw_ostream.h" @@ -33,11 +34,11 @@ using namespace mlir; struct BlockInfoBuilder { using ValueSetT = Liveness::ValueSetT; - /// Fills the block builder with initial liveness information. - void build(Block *block) { - // Store block for further processing. - this->block = block; + /// Constructs an empty block builder. + BlockInfoBuilder() : block(nullptr) {} + /// Fills the block builder with initial liveness information. + BlockInfoBuilder(Block *block) : block(block) { // Mark all block arguments (phis) as defined. for (BlockArgument *argument : block->getArguments()) defValues.insert(argument); @@ -46,7 +47,6 @@ struct BlockInfoBuilder { // are inside this block or not (see outValues). for (Operation &operation : *block) for (Value *result : operation.getResults()) { - // Mark as defined defValues.insert(result); // Check whether this value will be in the outValues @@ -63,8 +63,12 @@ struct BlockInfoBuilder { // Check all operations for used operands. for (Operation &operation : block->getOperations()) - for (Value *operand : operation.getOperands()) - useValues.insert(operand); + for (Value *operand : operation.getOperands()) { + // If the operand is already defined in the scope of this + // block, we can skip the value in the use set. + if (!defValues.count(operand)) + useValues.insert(operand); + } } /// Updates live-in information of the current block. @@ -74,11 +78,12 @@ struct BlockInfoBuilder { /// false otherwise. bool updateLiveIn() { ValueSetT newIn = useValues; - newIn.insert(outValues.begin(), outValues.end()); - // Subtract defValues - for (Value *defValue : defValues) - newIn.erase(defValue); + llvm::set_union(newIn, outValues); + llvm::set_subtract(newIn, defValues); + // It is sufficient to check the set sizes (instead of their contents) + // since the live-in set can only grow monotonically during all update + // operations. if (newIn.size() == inValues.size()) return false; @@ -93,7 +98,7 @@ struct BlockInfoBuilder { void updateLiveOut(SourceT &source) { for (Block *succ : block->getSuccessors()) { BlockInfoBuilder &builder = source[succ]; - outValues.insert(builder.inValues.begin(), builder.inValues.end()); + llvm::set_union(outValues, builder.inValues); } } @@ -114,18 +119,17 @@ struct BlockInfoBuilder { }; /// Builds the internal liveness block mapping. -static void -buildBlockMapping(MutableArrayRef regions, - llvm::DenseMap &builders) { +static void buildBlockMapping(MutableArrayRef regions, + DenseMap &builders) { llvm::SetVector toProcess; // Initialize all block structures for (Region ®ion : regions) for (Block &block : region) { - auto &blockBuilder = builders[&block]; - blockBuilder.build(&block); + BlockInfoBuilder &builder = + builders.try_emplace(&block, &block).first->second; - if (blockBuilder.updateLiveIn()) + if (builder.updateLiveIn()) toProcess.insert(block.pred_begin(), block.pred_end()); } @@ -155,7 +159,7 @@ Liveness::Liveness(Operation *op) : operation(op) { build(op->getRegions()); } void Liveness::build(MutableArrayRef regions) { // Build internal block mapping. - llvm::DenseMap builders; + DenseMap builders; buildBlockMapping(regions, builders); // Store internal block data. @@ -172,8 +176,8 @@ void Liveness::build(MutableArrayRef regions) { /// Gets liveness info (if any) for the given value. Liveness::OperationListT Liveness::resolveLiveness(Value *value) const { OperationListT result; - llvm::SmallDenseSet visited; - llvm::SmallVector toProcess; + SmallPtrSet visited; + SmallVector toProcess; // Start with the defining block Block *currentBlock; @@ -258,9 +262,9 @@ void Liveness::print(raw_ostream &os) const { os << "// ---- Liveness -----\n"; // Builds unique block/value mappings for testing purposes. - llvm::DenseMap blockIds; - llvm::DenseMap operationIds; - llvm::DenseMap valueIds; + DenseMap blockIds; + DenseMap operationIds; + DenseMap valueIds; for (Region ®ion : operation->getRegions()) for (Block &block : region) { blockIds[&block] = blockIds.size();