xref: /freebsd/contrib/llvm-project/llvm/lib/CodeGen/SpillPlacement.h (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
10b57cec5SDimitry Andric //===- SpillPlacement.h - Optimal Spill Code Placement ---------*- C++ -*--===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This analysis computes the optimal spill code placement between basic blocks.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric // The runOnMachineFunction() method only precomputes some profiling information
120b57cec5SDimitry Andric // about the CFG. The real work is done by prepare(), addConstraints(), and
130b57cec5SDimitry Andric // finish() which are called by the register allocator.
140b57cec5SDimitry Andric //
150b57cec5SDimitry Andric // Given a variable that is live across multiple basic blocks, and given
160b57cec5SDimitry Andric // constraints on the basic blocks where the variable is live, determine which
170b57cec5SDimitry Andric // edge bundles should have the variable in a register and which edge bundles
180b57cec5SDimitry Andric // should have the variable in a stack slot.
190b57cec5SDimitry Andric //
200b57cec5SDimitry Andric // The returned bit vector can be used to place optimal spill code at basic
210b57cec5SDimitry Andric // block entries and exits. Spill code placement inside a basic block is not
220b57cec5SDimitry Andric // considered.
230b57cec5SDimitry Andric //
240b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric #ifndef LLVM_LIB_CODEGEN_SPILLPLACEMENT_H
270b57cec5SDimitry Andric #define LLVM_LIB_CODEGEN_SPILLPLACEMENT_H
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h"
300b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
310b57cec5SDimitry Andric #include "llvm/ADT/SparseSet.h"
320b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
330b57cec5SDimitry Andric #include "llvm/Support/BlockFrequency.h"
340b57cec5SDimitry Andric 
350b57cec5SDimitry Andric namespace llvm {
360b57cec5SDimitry Andric 
370b57cec5SDimitry Andric class BitVector;
380b57cec5SDimitry Andric class EdgeBundles;
390b57cec5SDimitry Andric class MachineBlockFrequencyInfo;
400b57cec5SDimitry Andric class MachineFunction;
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric class SpillPlacement : public MachineFunctionPass {
430b57cec5SDimitry Andric   struct Node;
4406c3fb27SDimitry Andric   const MachineFunction *MF = nullptr;
4506c3fb27SDimitry Andric   const EdgeBundles *bundles = nullptr;
4606c3fb27SDimitry Andric   const MachineBlockFrequencyInfo *MBFI = nullptr;
470b57cec5SDimitry Andric   Node *nodes = nullptr;
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric   // Nodes that are active in the current computation. Owned by the prepare()
500b57cec5SDimitry Andric   // caller.
5106c3fb27SDimitry Andric   BitVector *ActiveNodes = nullptr;
520b57cec5SDimitry Andric 
530b57cec5SDimitry Andric   // Nodes with active links. Populated by scanActiveBundles.
540b57cec5SDimitry Andric   SmallVector<unsigned, 8> Linked;
550b57cec5SDimitry Andric 
560b57cec5SDimitry Andric   // Nodes that went positive during the last call to scanActiveBundles or
570b57cec5SDimitry Andric   // iterate.
580b57cec5SDimitry Andric   SmallVector<unsigned, 8> RecentPositive;
590b57cec5SDimitry Andric 
600b57cec5SDimitry Andric   // Block frequencies are computed once. Indexed by block number.
610b57cec5SDimitry Andric   SmallVector<BlockFrequency, 8> BlockFrequencies;
620b57cec5SDimitry Andric 
630b57cec5SDimitry Andric   /// Decision threshold. A node gets the output value 0 if the weighted sum of
640b57cec5SDimitry Andric   /// its inputs falls in the open interval (-Threshold;Threshold).
650b57cec5SDimitry Andric   BlockFrequency Threshold;
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric   /// List of nodes that need to be updated in ::iterate.
680b57cec5SDimitry Andric   SparseSet<unsigned> TodoList;
690b57cec5SDimitry Andric 
700b57cec5SDimitry Andric public:
710b57cec5SDimitry Andric   static char ID; // Pass identification, replacement for typeid.
720b57cec5SDimitry Andric 
730b57cec5SDimitry Andric   SpillPlacement() : MachineFunctionPass(ID) {}
740b57cec5SDimitry Andric   ~SpillPlacement() override { releaseMemory(); }
750b57cec5SDimitry Andric 
760b57cec5SDimitry Andric   /// BorderConstraint - A basic block has separate constraints for entry and
770b57cec5SDimitry Andric   /// exit.
780b57cec5SDimitry Andric   enum BorderConstraint {
790b57cec5SDimitry Andric     DontCare,  ///< Block doesn't care / variable not live.
800b57cec5SDimitry Andric     PrefReg,   ///< Block entry/exit prefers a register.
810b57cec5SDimitry Andric     PrefSpill, ///< Block entry/exit prefers a stack slot.
820b57cec5SDimitry Andric     PrefBoth,  ///< Block entry prefers both register and stack.
830b57cec5SDimitry Andric     MustSpill  ///< A register is impossible, variable must be spilled.
840b57cec5SDimitry Andric   };
850b57cec5SDimitry Andric 
860b57cec5SDimitry Andric   /// BlockConstraint - Entry and exit constraints for a basic block.
870b57cec5SDimitry Andric   struct BlockConstraint {
880b57cec5SDimitry Andric     unsigned Number;            ///< Basic block number (from MBB::getNumber()).
890b57cec5SDimitry Andric     BorderConstraint Entry : 8; ///< Constraint on block entry.
900b57cec5SDimitry Andric     BorderConstraint Exit : 8;  ///< Constraint on block exit.
910b57cec5SDimitry Andric 
920b57cec5SDimitry Andric     /// True when this block changes the value of the live range. This means
930b57cec5SDimitry Andric     /// the block has a non-PHI def.  When this is false, a live-in value on
940b57cec5SDimitry Andric     /// the stack can be live-out on the stack without inserting a spill.
950b57cec5SDimitry Andric     bool ChangesValue;
96fe6060f1SDimitry Andric 
97fe6060f1SDimitry Andric     void print(raw_ostream &OS) const;
98fe6060f1SDimitry Andric     void dump() const;
990b57cec5SDimitry Andric   };
1000b57cec5SDimitry Andric 
1010b57cec5SDimitry Andric   /// prepare - Reset state and prepare for a new spill placement computation.
1020b57cec5SDimitry Andric   /// @param RegBundles Bit vector to receive the edge bundles where the
1030b57cec5SDimitry Andric   ///                   variable should be kept in a register. Each bit
1040b57cec5SDimitry Andric   ///                   corresponds to an edge bundle, a set bit means the
1050b57cec5SDimitry Andric   ///                   variable should be kept in a register through the
1060b57cec5SDimitry Andric   ///                   bundle. A clear bit means the variable should be
1070b57cec5SDimitry Andric   ///                   spilled. This vector is retained.
1080b57cec5SDimitry Andric   void prepare(BitVector &RegBundles);
1090b57cec5SDimitry Andric 
1100b57cec5SDimitry Andric   /// addConstraints - Add constraints and biases. This method may be called
1110b57cec5SDimitry Andric   /// more than once to accumulate constraints.
1120b57cec5SDimitry Andric   /// @param LiveBlocks Constraints for blocks that have the variable live in or
1130b57cec5SDimitry Andric   ///                   live out.
1140b57cec5SDimitry Andric   void addConstraints(ArrayRef<BlockConstraint> LiveBlocks);
1150b57cec5SDimitry Andric 
1160b57cec5SDimitry Andric   /// addPrefSpill - Add PrefSpill constraints to all blocks listed.  This is
1170b57cec5SDimitry Andric   /// equivalent to calling addConstraint with identical BlockConstraints with
1180b57cec5SDimitry Andric   /// Entry = Exit = PrefSpill, and ChangesValue = false.
1190b57cec5SDimitry Andric   ///
1200b57cec5SDimitry Andric   /// @param Blocks Array of block numbers that prefer to spill in and out.
1210b57cec5SDimitry Andric   /// @param Strong When true, double the negative bias for these blocks.
1220b57cec5SDimitry Andric   void addPrefSpill(ArrayRef<unsigned> Blocks, bool Strong);
1230b57cec5SDimitry Andric 
1240b57cec5SDimitry Andric   /// addLinks - Add transparent blocks with the given numbers.
1250b57cec5SDimitry Andric   void addLinks(ArrayRef<unsigned> Links);
1260b57cec5SDimitry Andric 
1270b57cec5SDimitry Andric   /// scanActiveBundles - Perform an initial scan of all bundles activated by
1280b57cec5SDimitry Andric   /// addConstraints and addLinks, updating their state. Add all the bundles
1290b57cec5SDimitry Andric   /// that now prefer a register to RecentPositive.
1300b57cec5SDimitry Andric   /// Prepare internal data structures for iterate.
1310b57cec5SDimitry Andric   /// Return true is there are any positive nodes.
1320b57cec5SDimitry Andric   bool scanActiveBundles();
1330b57cec5SDimitry Andric 
1340b57cec5SDimitry Andric   /// iterate - Update the network iteratively until convergence, or new bundles
1350b57cec5SDimitry Andric   /// are found.
1360b57cec5SDimitry Andric   void iterate();
1370b57cec5SDimitry Andric 
1380b57cec5SDimitry Andric   /// getRecentPositive - Return an array of bundles that became positive during
1390b57cec5SDimitry Andric   /// the previous call to scanActiveBundles or iterate.
1400b57cec5SDimitry Andric   ArrayRef<unsigned> getRecentPositive() { return RecentPositive; }
1410b57cec5SDimitry Andric 
1420b57cec5SDimitry Andric   /// finish - Compute the optimal spill code placement given the
1430b57cec5SDimitry Andric   /// constraints. No MustSpill constraints will be violated, and the smallest
1440b57cec5SDimitry Andric   /// possible number of PrefX constraints will be violated, weighted by
1450b57cec5SDimitry Andric   /// expected execution frequencies.
1460b57cec5SDimitry Andric   /// The selected bundles are returned in the bitvector passed to prepare().
1470b57cec5SDimitry Andric   /// @return True if a perfect solution was found, allowing the variable to be
1480b57cec5SDimitry Andric   ///         in a register through all relevant bundles.
1490b57cec5SDimitry Andric   bool finish();
1500b57cec5SDimitry Andric 
1510b57cec5SDimitry Andric   /// getBlockFrequency - Return the estimated block execution frequency per
1520b57cec5SDimitry Andric   /// function invocation.
1530b57cec5SDimitry Andric   BlockFrequency getBlockFrequency(unsigned Number) const {
1540b57cec5SDimitry Andric     return BlockFrequencies[Number];
1550b57cec5SDimitry Andric   }
1560b57cec5SDimitry Andric 
1570b57cec5SDimitry Andric private:
1580b57cec5SDimitry Andric   bool runOnMachineFunction(MachineFunction &mf) override;
1590b57cec5SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override;
1600b57cec5SDimitry Andric   void releaseMemory() override;
1610b57cec5SDimitry Andric 
1620b57cec5SDimitry Andric   void activate(unsigned n);
163*5f757f3fSDimitry Andric   void setThreshold(BlockFrequency Entry);
1640b57cec5SDimitry Andric 
1650b57cec5SDimitry Andric   bool update(unsigned n);
1660b57cec5SDimitry Andric };
1670b57cec5SDimitry Andric 
1680b57cec5SDimitry Andric } // end namespace llvm
1690b57cec5SDimitry Andric 
1700b57cec5SDimitry Andric #endif // LLVM_LIB_CODEGEN_SPILLPLACEMENT_H
171