|  | //===- subzero/src/IceLiveness.h - Liveness analysis ------------*- C++ -*-===// | 
|  | // | 
|  | //                        The Subzero Code Generator | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | /// | 
|  | /// \file | 
|  | /// \brief Declares the Liveness and LivenessNode classes, which are used for | 
|  | /// liveness analysis. | 
|  | /// | 
|  | /// The node-specific information tracked for each Variable includes whether it | 
|  | /// is live on entry, whether it is live on exit, the instruction number that | 
|  | /// starts its live range, and the instruction number that ends its live range. | 
|  | /// At the Cfg level, the actual live intervals are recorded. | 
|  | /// | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #ifndef SUBZERO_SRC_ICELIVENESS_H | 
|  | #define SUBZERO_SRC_ICELIVENESS_H | 
|  |  | 
|  | #include "IceDefs.h" | 
|  | #include "IceBitVector.h" | 
|  | #include "IceCfgNode.h" | 
|  | #include "IceTLS.h" | 
|  | #include "IceTypes.h" | 
|  |  | 
|  | #include <memory> | 
|  | #include <utility> | 
|  |  | 
|  | namespace Ice { | 
|  |  | 
|  | class Liveness { | 
|  | Liveness() = delete; | 
|  | Liveness(const Liveness &) = delete; | 
|  | Liveness &operator=(const Liveness &) = delete; | 
|  |  | 
|  | class LivenessNode { | 
|  | LivenessNode &operator=(const LivenessNode &) = delete; | 
|  |  | 
|  | public: | 
|  | LivenessNode() = default; | 
|  | LivenessNode(const LivenessNode &) = default; | 
|  | /// NumLocals is the number of Variables local to this block. | 
|  | SizeT NumLocals = 0; | 
|  | /// NumNonDeadPhis tracks the number of Phi instructions that | 
|  | /// Inst::liveness() identified as tentatively live. If NumNonDeadPhis | 
|  | /// changes from the last liveness pass, then liveness has not yet | 
|  | /// converged. | 
|  | SizeT NumNonDeadPhis = 0; | 
|  | // LiveToVarMap maps a liveness bitvector index to a Variable. This is | 
|  | // generally just for printing/dumping. The index should be less than | 
|  | // NumLocals + Liveness::NumGlobals. | 
|  | LivenessVector<Variable *> LiveToVarMap; | 
|  | // LiveIn and LiveOut track the in- and out-liveness of the global | 
|  | // variables. The size of each vector is LivenessNode::NumGlobals. | 
|  | LivenessBV LiveIn, LiveOut; | 
|  | // LiveBegin and LiveEnd track the instruction numbers of the start and end | 
|  | // of each variable's live range within this block. The index/key of each | 
|  | // element is less than NumLocals + Liveness::NumGlobals. | 
|  | LiveBeginEndMap LiveBegin, LiveEnd; | 
|  | }; | 
|  |  | 
|  | public: | 
|  | void init(); | 
|  | void initPhiEdgeSplits(NodeList::const_iterator FirstNode, | 
|  | VarList::const_iterator FirstVar); | 
|  | Cfg *getFunc() const { return Func; } | 
|  | LivenessMode getMode() const { return Mode; } | 
|  | Variable *getVariable(SizeT LiveIndex, const CfgNode *Node) const; | 
|  | SizeT getLiveIndex(SizeT VarIndex) const { | 
|  | const SizeT LiveIndex = VarToLiveMap[VarIndex]; | 
|  | assert(LiveIndex != InvalidLiveIndex); | 
|  | return LiveIndex; | 
|  | } | 
|  | SizeT getNumGlobalVars() const { return NumGlobals; } | 
|  | SizeT getNumVarsInNode(const CfgNode *Node) const { | 
|  | return NumGlobals + Nodes[Node->getIndex()].NumLocals; | 
|  | } | 
|  | SizeT &getNumNonDeadPhis(const CfgNode *Node) { | 
|  | return Nodes[Node->getIndex()].NumNonDeadPhis; | 
|  | } | 
|  | LivenessBV &getLiveIn(const CfgNode *Node) { | 
|  | SizeT Index = Node->getIndex(); | 
|  | resize(Index); | 
|  | return Nodes[Index].LiveIn; | 
|  | } | 
|  | LivenessBV &getLiveOut(const CfgNode *Node) { | 
|  | SizeT Index = Node->getIndex(); | 
|  | resize(Index); | 
|  | return Nodes[Index].LiveOut; | 
|  | } | 
|  | LivenessBV &getScratchBV() { return ScratchBV; } | 
|  | LiveBeginEndMap *getLiveBegin(const CfgNode *Node) { | 
|  | SizeT Index = Node->getIndex(); | 
|  | resize(Index); | 
|  | return &Nodes[Index].LiveBegin; | 
|  | } | 
|  | LiveBeginEndMap *getLiveEnd(const CfgNode *Node) { | 
|  | SizeT Index = Node->getIndex(); | 
|  | resize(Index); | 
|  | return &Nodes[Index].LiveEnd; | 
|  | } | 
|  | bool getRangeMask(SizeT Index) const { return RangeMask[Index]; } | 
|  |  | 
|  | ArenaAllocator *getAllocator() const { return Alloc.get(); } | 
|  |  | 
|  | static std::unique_ptr<Liveness> create(Cfg *Func, LivenessMode Mode) { | 
|  | return std::unique_ptr<Liveness>(new Liveness(Func, Mode)); | 
|  | } | 
|  |  | 
|  | static void TlsInit() { LivenessAllocatorTraits::init(); } | 
|  |  | 
|  | std::string dumpStr() const { | 
|  | return "MaxLocals(" + std::to_string(MaxLocals) + "), " | 
|  | "NumGlobals(" + | 
|  | std::to_string(NumGlobals) + ")"; | 
|  | } | 
|  |  | 
|  | private: | 
|  | Liveness(Cfg *Func, LivenessMode Mode) | 
|  | : Alloc(new ArenaAllocator()), AllocScope(this), Func(Func), Mode(Mode) {} | 
|  |  | 
|  | void initInternal(NodeList::const_iterator FirstNode, | 
|  | VarList::const_iterator FirstVar, bool IsFullInit); | 
|  | /// Resize Nodes so that Nodes[Index] is valid. | 
|  | void resize(SizeT Index) { | 
|  | if (Index >= Nodes.size()) { | 
|  | assert(false && "The Nodes array is not expected to be resized."); | 
|  | Nodes.resize(Index + 1); | 
|  | } | 
|  | } | 
|  | std::unique_ptr<ArenaAllocator> Alloc; | 
|  | LivenessAllocatorScope AllocScope; // Must be declared after Alloc. | 
|  | static constexpr SizeT InvalidLiveIndex = -1; | 
|  | Cfg *Func; | 
|  | LivenessMode Mode; | 
|  | /// Size of Nodes is Cfg::Nodes.size(). | 
|  | LivenessVector<LivenessNode> Nodes; | 
|  | /// VarToLiveMap maps a Variable's Variable::Number to its live index within | 
|  | /// its basic block. | 
|  | LivenessVector<SizeT> VarToLiveMap; | 
|  | /// LiveToVarMap is analogous to LivenessNode::LiveToVarMap, but for non-local | 
|  | /// variables. | 
|  | LivenessVector<Variable *> LiveToVarMap; | 
|  | /// RangeMask[Variable::Number] indicates whether we want to track that | 
|  | /// Variable's live range. | 
|  | LivenessBV RangeMask; | 
|  | /// ScratchBV is a bitvector that can be reused across CfgNode passes, to | 
|  | /// avoid having to allocate/deallocate memory so frequently. | 
|  | LivenessBV ScratchBV; | 
|  | /// MaxLocals indicates what is the maximum number of local variables in a | 
|  | /// single basic block, across all blocks in a function. | 
|  | SizeT MaxLocals = 0; | 
|  | /// NumGlobals indicates how many global variables (i.e., Multi Block) exist | 
|  | /// for a function. | 
|  | SizeT NumGlobals = 0; | 
|  | }; | 
|  |  | 
|  | } // end of namespace Ice | 
|  |  | 
|  | #endif // SUBZERO_SRC_ICELIVENESS_H |