Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:43:31

0001 //===---- MachineOutliner.h - Outliner data structures ------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 ///
0009 /// \file
0010 /// Contains all data structures shared between the outliner implemented in
0011 /// MachineOutliner.cpp and target implementations of the outliner.
0012 ///
0013 //===----------------------------------------------------------------------===//
0014 
0015 #ifndef LLVM_CODEGEN_MACHINEOUTLINER_H
0016 #define LLVM_CODEGEN_MACHINEOUTLINER_H
0017 
0018 #include "llvm/CodeGen/LiveRegUnits.h"
0019 #include "llvm/CodeGen/MachineFunction.h"
0020 #include "llvm/CodeGen/MachineRegisterInfo.h"
0021 #include "llvm/CodeGen/MachineStableHash.h"
0022 #include <initializer_list>
0023 
0024 namespace llvm {
0025 namespace outliner {
0026 
0027 /// Represents how an instruction should be mapped by the outliner.
0028 /// \p Legal instructions are those which are safe to outline.
0029 /// \p LegalTerminator instructions are safe to outline, but only as the
0030 /// last instruction in a sequence.
0031 /// \p Illegal instructions are those which cannot be outlined.
0032 /// \p Invisible instructions are instructions which can be outlined, but
0033 /// shouldn't actually impact the outlining result.
0034 enum InstrType { Legal, LegalTerminator, Illegal, Invisible };
0035 
0036 /// An individual sequence of instructions to be replaced with a call to
0037 /// an outlined function.
0038 struct Candidate {
0039 private:
0040   /// The start index of this \p Candidate in the instruction list.
0041   unsigned StartIdx = 0;
0042 
0043   /// The number of instructions in this \p Candidate.
0044   unsigned Len = 0;
0045 
0046   // The first instruction in this \p Candidate.
0047   MachineBasicBlock::iterator FirstInst;
0048 
0049   // The last instruction in this \p Candidate.
0050   MachineBasicBlock::iterator LastInst;
0051 
0052   // The basic block that contains this Candidate.
0053   MachineBasicBlock *MBB = nullptr;
0054 
0055   /// Cost of calling an outlined function from this point as defined by the
0056   /// target.
0057   unsigned CallOverhead = 0;
0058 
0059   /// Liveness information for this Candidate. Tracks from the end of the
0060   /// block containing this Candidate to the beginning of its sequence.
0061   ///
0062   /// Optional. Can be used to fine-tune the cost model, or fine-tune legality
0063   /// decisions.
0064   LiveRegUnits FromEndOfBlockToStartOfSeq;
0065 
0066   /// Liveness information restricted to this Candidate's instruction sequence.
0067   ///
0068   /// Optional. Can be used to fine-tune the cost model, or fine-tune legality
0069   /// decisions.
0070   LiveRegUnits InSeq;
0071 
0072   /// True if FromEndOfBlockToStartOfSeq has been initialized.
0073   bool FromEndOfBlockToStartOfSeqWasSet = false;
0074 
0075   /// True if InSeq has been initialized.
0076   bool InSeqWasSet = false;
0077 
0078   /// Populate FromEndOfBlockToStartOfSeq with liveness information.
0079   void initFromEndOfBlockToStartOfSeq(const TargetRegisterInfo &TRI) {
0080     assert(MBB->getParent()->getRegInfo().tracksLiveness() &&
0081            "Candidate's Machine Function must track liveness");
0082     // Only initialize once.
0083     if (FromEndOfBlockToStartOfSeqWasSet)
0084       return;
0085     FromEndOfBlockToStartOfSeqWasSet = true;
0086     FromEndOfBlockToStartOfSeq.init(TRI);
0087     FromEndOfBlockToStartOfSeq.addLiveOuts(*MBB);
0088     // Compute liveness from the end of the block up to the beginning of the
0089     // outlining candidate.
0090     for (auto &MI : make_range(MBB->rbegin(),
0091                                (MachineBasicBlock::reverse_iterator)begin()))
0092       FromEndOfBlockToStartOfSeq.stepBackward(MI);
0093   }
0094 
0095   /// Populate InSeq with liveness information.
0096   void initInSeq(const TargetRegisterInfo &TRI) {
0097     assert(MBB->getParent()->getRegInfo().tracksLiveness() &&
0098            "Candidate's Machine Function must track liveness");
0099     // Only initialize once.
0100     if (InSeqWasSet)
0101       return;
0102     InSeqWasSet = true;
0103     InSeq.init(TRI);
0104     for (auto &MI : *this)
0105       InSeq.accumulate(MI);
0106   }
0107 
0108 public:
0109   /// The index of this \p Candidate's \p OutlinedFunction in the list of
0110   /// \p OutlinedFunctions.
0111   unsigned FunctionIdx = 0;
0112 
0113   /// Identifier denoting the instructions to emit to call an outlined function
0114   /// from this point. Defined by the target.
0115   unsigned CallConstructionID = 0;
0116 
0117   /// Target-specific flags for this Candidate's MBB.
0118   unsigned Flags = 0x0;
0119 
0120   /// Return the number of instructions in this Candidate.
0121   unsigned getLength() const { return Len; }
0122 
0123   /// Return the start index of this candidate.
0124   unsigned getStartIdx() const { return StartIdx; }
0125 
0126   /// Return the end index of this candidate.
0127   unsigned getEndIdx() const { return StartIdx + Len - 1; }
0128 
0129   /// Set the CallConstructionID and CallOverhead of this candidate to CID and
0130   /// CO respectively.
0131   void setCallInfo(unsigned CID, unsigned CO) {
0132     CallConstructionID = CID;
0133     CallOverhead = CO;
0134   }
0135 
0136   /// Returns the call overhead of this candidate if it is in the list.
0137   unsigned getCallOverhead() const { return CallOverhead; }
0138 
0139   MachineBasicBlock::iterator begin() { return FirstInst; }
0140   MachineBasicBlock::iterator end() { return std::next(LastInst); }
0141 
0142   MachineInstr &front() { return *FirstInst; }
0143   MachineInstr &back() { return *LastInst; }
0144   MachineFunction *getMF() const { return MBB->getParent(); }
0145   MachineBasicBlock *getMBB() const { return MBB; }
0146 
0147   /// \returns True if \p Reg is available from the end of the block to the
0148   /// beginning of the sequence.
0149   ///
0150   /// This query considers the following range:
0151   ///
0152   /// in_seq_1
0153   /// in_seq_2
0154   /// ...
0155   /// in_seq_n
0156   /// not_in_seq_1
0157   /// ...
0158   /// <end of block>
0159   bool isAvailableAcrossAndOutOfSeq(Register Reg,
0160                                     const TargetRegisterInfo &TRI) {
0161     if (!FromEndOfBlockToStartOfSeqWasSet)
0162       initFromEndOfBlockToStartOfSeq(TRI);
0163     return FromEndOfBlockToStartOfSeq.available(Reg);
0164   }
0165 
0166   /// \returns True if `isAvailableAcrossAndOutOfSeq` fails for any register
0167   /// in \p Regs.
0168   bool isAnyUnavailableAcrossOrOutOfSeq(std::initializer_list<Register> Regs,
0169                                         const TargetRegisterInfo &TRI) {
0170     if (!FromEndOfBlockToStartOfSeqWasSet)
0171       initFromEndOfBlockToStartOfSeq(TRI);
0172     return any_of(Regs, [&](Register Reg) {
0173       return !FromEndOfBlockToStartOfSeq.available(Reg);
0174     });
0175   }
0176 
0177   /// \returns True if \p Reg is available within the sequence itself.
0178   ///
0179   /// This query considers the following range:
0180   ///
0181   /// in_seq_1
0182   /// in_seq_2
0183   /// ...
0184   /// in_seq_n
0185   bool isAvailableInsideSeq(Register Reg, const TargetRegisterInfo &TRI) {
0186     if (!InSeqWasSet)
0187       initInSeq(TRI);
0188     return InSeq.available(Reg);
0189   }
0190 
0191   /// The number of instructions that would be saved by outlining every
0192   /// candidate of this type.
0193   ///
0194   /// This is a fixed value which is not updated during the candidate pruning
0195   /// process. It is only used for deciding which candidate to keep if two
0196   /// candidates overlap. The true benefit is stored in the OutlinedFunction
0197   /// for some given candidate.
0198   unsigned Benefit = 0;
0199 
0200   Candidate(unsigned StartIdx, unsigned Len,
0201             MachineBasicBlock::iterator &FirstInst,
0202             MachineBasicBlock::iterator &LastInst, MachineBasicBlock *MBB,
0203             unsigned FunctionIdx, unsigned Flags)
0204       : StartIdx(StartIdx), Len(Len), FirstInst(FirstInst), LastInst(LastInst),
0205         MBB(MBB), FunctionIdx(FunctionIdx), Flags(Flags) {}
0206   Candidate() = delete;
0207 
0208   /// Used to ensure that \p Candidates are outlined in an order that
0209   /// preserves the start and end indices of other \p Candidates.
0210   bool operator<(const Candidate &RHS) const {
0211     return getStartIdx() > RHS.getStartIdx();
0212   }
0213 
0214 };
0215 
0216 /// The information necessary to create an outlined function for some
0217 /// class of candidate.
0218 struct OutlinedFunction {
0219 
0220 public:
0221   std::vector<Candidate> Candidates;
0222 
0223   /// The actual outlined function created.
0224   /// This is initialized after we go through and create the actual function.
0225   MachineFunction *MF = nullptr;
0226 
0227   /// Represents the size of a sequence in bytes. (Some instructions vary
0228   /// widely in size, so just counting the instructions isn't very useful.)
0229   unsigned SequenceSize = 0;
0230 
0231   /// Target-defined overhead of constructing a frame for this function.
0232   unsigned FrameOverhead = 0;
0233 
0234   /// Target-defined identifier for constructing a frame for this function.
0235   unsigned FrameConstructionID = 0;
0236 
0237   /// Return the number of candidates for this \p OutlinedFunction.
0238   virtual unsigned getOccurrenceCount() const { return Candidates.size(); }
0239 
0240   /// Return the number of bytes it would take to outline this
0241   /// function.
0242   virtual unsigned getOutliningCost() const {
0243     unsigned CallOverhead = 0;
0244     for (const Candidate &C : Candidates)
0245       CallOverhead += C.getCallOverhead();
0246     return CallOverhead + SequenceSize + FrameOverhead;
0247   }
0248 
0249   /// Return the size in bytes of the unoutlined sequences.
0250   unsigned getNotOutlinedCost() const {
0251     return getOccurrenceCount() * SequenceSize;
0252   }
0253 
0254   /// Return the number of instructions that would be saved by outlining
0255   /// this function.
0256   unsigned getBenefit() const {
0257     unsigned NotOutlinedCost = getNotOutlinedCost();
0258     unsigned OutlinedCost = getOutliningCost();
0259     return (NotOutlinedCost < OutlinedCost) ? 0
0260                                             : NotOutlinedCost - OutlinedCost;
0261   }
0262 
0263   /// Return the number of instructions in this sequence.
0264   unsigned getNumInstrs() const { return Candidates[0].getLength(); }
0265 
0266   OutlinedFunction(std::vector<Candidate> &Candidates, unsigned SequenceSize,
0267                    unsigned FrameOverhead, unsigned FrameConstructionID)
0268       : Candidates(Candidates), SequenceSize(SequenceSize),
0269         FrameOverhead(FrameOverhead), FrameConstructionID(FrameConstructionID) {
0270     const unsigned B = getBenefit();
0271     for (Candidate &C : Candidates)
0272       C.Benefit = B;
0273   }
0274 
0275   OutlinedFunction() = delete;
0276   virtual ~OutlinedFunction() = default;
0277 };
0278 
0279 /// The information necessary to create an outlined function that is matched
0280 /// globally.
0281 struct GlobalOutlinedFunction : public OutlinedFunction {
0282   explicit GlobalOutlinedFunction(std::unique_ptr<OutlinedFunction> OF,
0283                                   unsigned GlobalOccurrenceCount)
0284       : OutlinedFunction(*OF), GlobalOccurrenceCount(GlobalOccurrenceCount) {}
0285 
0286   unsigned GlobalOccurrenceCount;
0287 
0288   /// Return the number of times that appear globally.
0289   /// Global outlining candidate is uniquely created per each match, but this
0290   /// might be erased out when it's overlapped with the previous outlining
0291   /// instance.
0292   unsigned getOccurrenceCount() const override {
0293     assert(Candidates.size() <= 1);
0294     return Candidates.empty() ? 0 : GlobalOccurrenceCount;
0295   }
0296 
0297   /// Return the outlining cost using the global occurrence count
0298   /// with the same cost as the first (unique) candidate.
0299   unsigned getOutliningCost() const override {
0300     assert(Candidates.size() <= 1);
0301     unsigned CallOverhead =
0302         Candidates.empty()
0303             ? 0
0304             : Candidates[0].getCallOverhead() * getOccurrenceCount();
0305     return CallOverhead + SequenceSize + FrameOverhead;
0306   }
0307 
0308   GlobalOutlinedFunction() = delete;
0309   ~GlobalOutlinedFunction() = default;
0310 };
0311 
0312 } // namespace outliner
0313 } // namespace llvm
0314 
0315 #endif