//===- Liveness.h - Liveness analysis for MLIR ------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file contains an analysis for computing liveness information from a // given top-level operation. The current version of the analysis uses a // traditional algorithm to resolve detailed live-range information about all // values within the specified regions. It is also possible to query liveness // information on block level. // //===----------------------------------------------------------------------===// #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/SmallPtrSet.h" namespace mlir { class Block; class LivenessBlockInfo; class Operation; class Region; class Value; /// Represents an analysis for computing liveness information from a /// given top-level operation. The analysis iterates over all associated /// regions that are attached to the given top-level operation. It /// computes liveness information for every value and block that are /// 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 isDeafAfter = liveness.isDeadAfter(value, operation); class Liveness { public: using OperationListT = std::vector; using BlockMapT = DenseMap; using ValueSetT = SmallPtrSet; public: /// Creates a new Liveness analysis that computes liveness /// information for all associated regions. Liveness(Operation *op); /// Returns the operation this analysis was constructed from. Operation *getOperation() const { return operation; } /// 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 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. const LivenessBlockInfo *getLiveness(Block *block) const; /// Returns a reference to a set containing live-in values (unordered). const ValueSetT &getLiveIn(Block *block) const; /// Returns a reference to a set containing live-out values (unordered). const ValueSetT &getLiveOut(Block *block) const; /// Returns true if `value` is not live after `operation`. bool isDeadAfter(Value value, Operation *operation) const; /// Dumps the liveness information in a human readable format. void dump() const; /// Dumps the liveness information to the given stream. void print(raw_ostream &os) const; private: /// Initializes the internal mappings. void build(); private: /// The operation this analysis was constructed from. Operation *operation; /// Maps blocks to internal liveness information. BlockMapT blockMapping; }; /// This class represents liveness information on block level. class LivenessBlockInfo { public: /// A typedef declaration of a value set. using ValueSetT = Liveness::ValueSetT; public: /// Returns the underlying block. Block *getBlock() const { return block; } /// Returns all values that are live at the beginning /// of the block (unordered). const ValueSetT &in() const { return inValues; } /// Returns all values that are live at the end /// of the block (unordered). const ValueSetT &out() const { return outValues; } /// Returns true if the given value is in the live-in set. bool isLiveIn(Value value) const; /// 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. 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 /// provided (must be referenced in this block). Operation *getEndOperation(Value value, Operation *startOperation) const; /// Get the set of values that are currently live (if any) for the current op. /// This analysis takes an expansive view of "live" in that if a value is /// defined by or within the operation or is fully consumed (as in last user) /// by or within the operation the value is considered "live". The values in /// the list are not ordered. /// /// This check is quite expensive as it does not cache the results of the /// computation, so the currently live values have to be recomputed for each /// op. ValueSetT currentlyLiveValues(Operation *op) const; private: /// The underlying block. Block *block = nullptr; /// The set of all live in values. ValueSetT inValues; /// The set of all live out values. ValueSetT outValues; friend class Liveness; }; } // namespace mlir #endif // MLIR_ANALYSIS_LIVENESS_H