| //===- SpillPlacement.h - Optimal Spill Code Placement ---------*- 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 analysis computes the optimal spill code placement between basic blocks. |
| // |
| // The runOnMachineFunction() method only precomputes some profiling information |
| // about the CFG. The real work is done by prepare(), addConstraints(), and |
| // finish() which are called by the register allocator. |
| // |
| // Given a variable that is live across multiple basic blocks, and given |
| // constraints on the basic blocks where the variable is live, determine which |
| // edge bundles should have the variable in a register and which edge bundles |
| // should have the variable in a stack slot. |
| // |
| // The returned bit vector can be used to place optimal spill code at basic |
| // block entries and exits. Spill code placement inside a basic block is not |
| // considered. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_LIB_CODEGEN_SPILLPLACEMENT_H |
| #define LLVM_LIB_CODEGEN_SPILLPLACEMENT_H |
| |
| #include "llvm/ADT/ArrayRef.h" |
| #include "llvm/ADT/SmallVector.h" |
| #include "llvm/ADT/SparseSet.h" |
| #include "llvm/CodeGen/MachineFunctionPass.h" |
| #include "llvm/Support/BlockFrequency.h" |
| |
| namespace llvm { |
| |
| class BitVector; |
| class EdgeBundles; |
| class MachineBlockFrequencyInfo; |
| class MachineFunction; |
| class MachineLoopInfo; |
| |
| class SpillPlacement : public MachineFunctionPass { |
| struct Node; |
| const MachineFunction *MF; |
| const EdgeBundles *bundles; |
| const MachineLoopInfo *loops; |
| const MachineBlockFrequencyInfo *MBFI; |
| Node *nodes = nullptr; |
| |
| // Nodes that are active in the current computation. Owned by the prepare() |
| // caller. |
| BitVector *ActiveNodes; |
| |
| // Nodes with active links. Populated by scanActiveBundles. |
| SmallVector<unsigned, 8> Linked; |
| |
| // Nodes that went positive during the last call to scanActiveBundles or |
| // iterate. |
| SmallVector<unsigned, 8> RecentPositive; |
| |
| // Block frequencies are computed once. Indexed by block number. |
| SmallVector<BlockFrequency, 8> BlockFrequencies; |
| |
| /// Decision threshold. A node gets the output value 0 if the weighted sum of |
| /// its inputs falls in the open interval (-Threshold;Threshold). |
| BlockFrequency Threshold; |
| |
| /// List of nodes that need to be updated in ::iterate. |
| SparseSet<unsigned> TodoList; |
| |
| public: |
| static char ID; // Pass identification, replacement for typeid. |
| |
| SpillPlacement() : MachineFunctionPass(ID) {} |
| ~SpillPlacement() override { releaseMemory(); } |
| |
| /// BorderConstraint - A basic block has separate constraints for entry and |
| /// exit. |
| enum BorderConstraint { |
| DontCare, ///< Block doesn't care / variable not live. |
| PrefReg, ///< Block entry/exit prefers a register. |
| PrefSpill, ///< Block entry/exit prefers a stack slot. |
| PrefBoth, ///< Block entry prefers both register and stack. |
| MustSpill ///< A register is impossible, variable must be spilled. |
| }; |
| |
| /// BlockConstraint - Entry and exit constraints for a basic block. |
| struct BlockConstraint { |
| unsigned Number; ///< Basic block number (from MBB::getNumber()). |
| BorderConstraint Entry : 8; ///< Constraint on block entry. |
| BorderConstraint Exit : 8; ///< Constraint on block exit. |
| |
| /// True when this block changes the value of the live range. This means |
| /// the block has a non-PHI def. When this is false, a live-in value on |
| /// the stack can be live-out on the stack without inserting a spill. |
| bool ChangesValue; |
| |
| void print(raw_ostream &OS) const; |
| void dump() const; |
| }; |
| |
| /// prepare - Reset state and prepare for a new spill placement computation. |
| /// @param RegBundles Bit vector to receive the edge bundles where the |
| /// variable should be kept in a register. Each bit |
| /// corresponds to an edge bundle, a set bit means the |
| /// variable should be kept in a register through the |
| /// bundle. A clear bit means the variable should be |
| /// spilled. This vector is retained. |
| void prepare(BitVector &RegBundles); |
| |
| /// addConstraints - Add constraints and biases. This method may be called |
| /// more than once to accumulate constraints. |
| /// @param LiveBlocks Constraints for blocks that have the variable live in or |
| /// live out. |
| void addConstraints(ArrayRef<BlockConstraint> LiveBlocks); |
| |
| /// addPrefSpill - Add PrefSpill constraints to all blocks listed. This is |
| /// equivalent to calling addConstraint with identical BlockConstraints with |
| /// Entry = Exit = PrefSpill, and ChangesValue = false. |
| /// |
| /// @param Blocks Array of block numbers that prefer to spill in and out. |
| /// @param Strong When true, double the negative bias for these blocks. |
| void addPrefSpill(ArrayRef<unsigned> Blocks, bool Strong); |
| |
| /// addLinks - Add transparent blocks with the given numbers. |
| void addLinks(ArrayRef<unsigned> Links); |
| |
| /// scanActiveBundles - Perform an initial scan of all bundles activated by |
| /// addConstraints and addLinks, updating their state. Add all the bundles |
| /// that now prefer a register to RecentPositive. |
| /// Prepare internal data structures for iterate. |
| /// Return true is there are any positive nodes. |
| bool scanActiveBundles(); |
| |
| /// iterate - Update the network iteratively until convergence, or new bundles |
| /// are found. |
| void iterate(); |
| |
| /// getRecentPositive - Return an array of bundles that became positive during |
| /// the previous call to scanActiveBundles or iterate. |
| ArrayRef<unsigned> getRecentPositive() { return RecentPositive; } |
| |
| /// finish - Compute the optimal spill code placement given the |
| /// constraints. No MustSpill constraints will be violated, and the smallest |
| /// possible number of PrefX constraints will be violated, weighted by |
| /// expected execution frequencies. |
| /// The selected bundles are returned in the bitvector passed to prepare(). |
| /// @return True if a perfect solution was found, allowing the variable to be |
| /// in a register through all relevant bundles. |
| bool finish(); |
| |
| /// getBlockFrequency - Return the estimated block execution frequency per |
| /// function invocation. |
| BlockFrequency getBlockFrequency(unsigned Number) const { |
| return BlockFrequencies[Number]; |
| } |
| |
| private: |
| bool runOnMachineFunction(MachineFunction &mf) override; |
| void getAnalysisUsage(AnalysisUsage &AU) const override; |
| void releaseMemory() override; |
| |
| void activate(unsigned n); |
| void setThreshold(const BlockFrequency &Entry); |
| |
| bool update(unsigned n); |
| }; |
| |
| } // end namespace llvm |
| |
| #endif // LLVM_LIB_CODEGEN_SPILLPLACEMENT_H |