//===- 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 Linked; // Nodes that went positive during the last call to scanActiveBundles or // iterate. SmallVector RecentPositive; // Block frequencies are computed once. Indexed by block number. SmallVector 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 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 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 Blocks, bool Strong); /// addLinks - Add transparent blocks with the given numbers. void addLinks(ArrayRef 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 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