xref: /llvm-project/llvm/include/llvm/CodeGen/MachineOutliner.h (revision 0f525452896771cc8c579eb362dc7645e38fd0b9)
1 //===---- MachineOutliner.h - Outliner data structures ------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 /// \file
10 /// Contains all data structures shared between the outliner implemented in
11 /// MachineOutliner.cpp and target implementations of the outliner.
12 ///
13 //===----------------------------------------------------------------------===//
14 
15 #ifndef LLVM_CODEGEN_MACHINEOUTLINER_H
16 #define LLVM_CODEGEN_MACHINEOUTLINER_H
17 
18 #include "llvm/CodeGen/LiveRegUnits.h"
19 #include "llvm/CodeGen/MachineFunction.h"
20 #include "llvm/CodeGen/MachineRegisterInfo.h"
21 #include "llvm/CodeGen/MachineStableHash.h"
22 #include <initializer_list>
23 
24 namespace llvm {
25 namespace outliner {
26 
27 /// Represents how an instruction should be mapped by the outliner.
28 /// \p Legal instructions are those which are safe to outline.
29 /// \p LegalTerminator instructions are safe to outline, but only as the
30 /// last instruction in a sequence.
31 /// \p Illegal instructions are those which cannot be outlined.
32 /// \p Invisible instructions are instructions which can be outlined, but
33 /// shouldn't actually impact the outlining result.
34 enum InstrType { Legal, LegalTerminator, Illegal, Invisible };
35 
36 /// An individual sequence of instructions to be replaced with a call to
37 /// an outlined function.
38 struct Candidate {
39 private:
40   /// The start index of this \p Candidate in the instruction list.
41   unsigned StartIdx = 0;
42 
43   /// The number of instructions in this \p Candidate.
44   unsigned Len = 0;
45 
46   // The first instruction in this \p Candidate.
47   MachineBasicBlock::iterator FirstInst;
48 
49   // The last instruction in this \p Candidate.
50   MachineBasicBlock::iterator LastInst;
51 
52   // The basic block that contains this Candidate.
53   MachineBasicBlock *MBB = nullptr;
54 
55   /// Cost of calling an outlined function from this point as defined by the
56   /// target.
57   unsigned CallOverhead = 0;
58 
59   /// Liveness information for this Candidate. Tracks from the end of the
60   /// block containing this Candidate to the beginning of its sequence.
61   ///
62   /// Optional. Can be used to fine-tune the cost model, or fine-tune legality
63   /// decisions.
64   LiveRegUnits FromEndOfBlockToStartOfSeq;
65 
66   /// Liveness information restricted to this Candidate's instruction sequence.
67   ///
68   /// Optional. Can be used to fine-tune the cost model, or fine-tune legality
69   /// decisions.
70   LiveRegUnits InSeq;
71 
72   /// True if FromEndOfBlockToStartOfSeq has been initialized.
73   bool FromEndOfBlockToStartOfSeqWasSet = false;
74 
75   /// True if InSeq has been initialized.
76   bool InSeqWasSet = false;
77 
78   /// Populate FromEndOfBlockToStartOfSeq with liveness information.
79   void initFromEndOfBlockToStartOfSeq(const TargetRegisterInfo &TRI) {
80     assert(MBB->getParent()->getRegInfo().tracksLiveness() &&
81            "Candidate's Machine Function must track liveness");
82     // Only initialize once.
83     if (FromEndOfBlockToStartOfSeqWasSet)
84       return;
85     FromEndOfBlockToStartOfSeqWasSet = true;
86     FromEndOfBlockToStartOfSeq.init(TRI);
87     FromEndOfBlockToStartOfSeq.addLiveOuts(*MBB);
88     // Compute liveness from the end of the block up to the beginning of the
89     // outlining candidate.
90     for (auto &MI : make_range(MBB->rbegin(),
91                                (MachineBasicBlock::reverse_iterator)begin()))
92       FromEndOfBlockToStartOfSeq.stepBackward(MI);
93   }
94 
95   /// Populate InSeq with liveness information.
96   void initInSeq(const TargetRegisterInfo &TRI) {
97     assert(MBB->getParent()->getRegInfo().tracksLiveness() &&
98            "Candidate's Machine Function must track liveness");
99     // Only initialize once.
100     if (InSeqWasSet)
101       return;
102     InSeqWasSet = true;
103     InSeq.init(TRI);
104     for (auto &MI : *this)
105       InSeq.accumulate(MI);
106   }
107 
108 public:
109   /// The index of this \p Candidate's \p OutlinedFunction in the list of
110   /// \p OutlinedFunctions.
111   unsigned FunctionIdx = 0;
112 
113   /// Identifier denoting the instructions to emit to call an outlined function
114   /// from this point. Defined by the target.
115   unsigned CallConstructionID = 0;
116 
117   /// Target-specific flags for this Candidate's MBB.
118   unsigned Flags = 0x0;
119 
120   /// Return the number of instructions in this Candidate.
121   unsigned getLength() const { return Len; }
122 
123   /// Return the start index of this candidate.
124   unsigned getStartIdx() const { return StartIdx; }
125 
126   /// Return the end index of this candidate.
127   unsigned getEndIdx() const { return StartIdx + Len - 1; }
128 
129   /// Set the CallConstructionID and CallOverhead of this candidate to CID and
130   /// CO respectively.
131   void setCallInfo(unsigned CID, unsigned CO) {
132     CallConstructionID = CID;
133     CallOverhead = CO;
134   }
135 
136   /// Returns the call overhead of this candidate if it is in the list.
137   unsigned getCallOverhead() const { return CallOverhead; }
138 
139   MachineBasicBlock::iterator begin() { return FirstInst; }
140   MachineBasicBlock::iterator end() { return std::next(LastInst); }
141 
142   MachineInstr &front() { return *FirstInst; }
143   MachineInstr &back() { return *LastInst; }
144   MachineFunction *getMF() const { return MBB->getParent(); }
145   MachineBasicBlock *getMBB() const { return MBB; }
146 
147   /// \returns True if \p Reg is available from the end of the block to the
148   /// beginning of the sequence.
149   ///
150   /// This query considers the following range:
151   ///
152   /// in_seq_1
153   /// in_seq_2
154   /// ...
155   /// in_seq_n
156   /// not_in_seq_1
157   /// ...
158   /// <end of block>
159   bool isAvailableAcrossAndOutOfSeq(Register Reg,
160                                     const TargetRegisterInfo &TRI) {
161     if (!FromEndOfBlockToStartOfSeqWasSet)
162       initFromEndOfBlockToStartOfSeq(TRI);
163     return FromEndOfBlockToStartOfSeq.available(Reg);
164   }
165 
166   /// \returns True if `isAvailableAcrossAndOutOfSeq` fails for any register
167   /// in \p Regs.
168   bool isAnyUnavailableAcrossOrOutOfSeq(std::initializer_list<Register> Regs,
169                                         const TargetRegisterInfo &TRI) {
170     if (!FromEndOfBlockToStartOfSeqWasSet)
171       initFromEndOfBlockToStartOfSeq(TRI);
172     return any_of(Regs, [&](Register Reg) {
173       return !FromEndOfBlockToStartOfSeq.available(Reg);
174     });
175   }
176 
177   /// \returns True if \p Reg is available within the sequence itself.
178   ///
179   /// This query considers the following range:
180   ///
181   /// in_seq_1
182   /// in_seq_2
183   /// ...
184   /// in_seq_n
185   bool isAvailableInsideSeq(Register Reg, const TargetRegisterInfo &TRI) {
186     if (!InSeqWasSet)
187       initInSeq(TRI);
188     return InSeq.available(Reg);
189   }
190 
191   /// The number of instructions that would be saved by outlining every
192   /// candidate of this type.
193   ///
194   /// This is a fixed value which is not updated during the candidate pruning
195   /// process. It is only used for deciding which candidate to keep if two
196   /// candidates overlap. The true benefit is stored in the OutlinedFunction
197   /// for some given candidate.
198   unsigned Benefit = 0;
199 
200   Candidate(unsigned StartIdx, unsigned Len,
201             MachineBasicBlock::iterator &FirstInst,
202             MachineBasicBlock::iterator &LastInst, MachineBasicBlock *MBB,
203             unsigned FunctionIdx, unsigned Flags)
204       : StartIdx(StartIdx), Len(Len), FirstInst(FirstInst), LastInst(LastInst),
205         MBB(MBB), FunctionIdx(FunctionIdx), Flags(Flags) {}
206   Candidate() = delete;
207 
208   /// Used to ensure that \p Candidates are outlined in an order that
209   /// preserves the start and end indices of other \p Candidates.
210   bool operator<(const Candidate &RHS) const {
211     return getStartIdx() > RHS.getStartIdx();
212   }
213 
214 };
215 
216 /// The information necessary to create an outlined function for some
217 /// class of candidate.
218 struct OutlinedFunction {
219 
220 public:
221   std::vector<Candidate> Candidates;
222 
223   /// The actual outlined function created.
224   /// This is initialized after we go through and create the actual function.
225   MachineFunction *MF = nullptr;
226 
227   /// Represents the size of a sequence in bytes. (Some instructions vary
228   /// widely in size, so just counting the instructions isn't very useful.)
229   unsigned SequenceSize = 0;
230 
231   /// Target-defined overhead of constructing a frame for this function.
232   unsigned FrameOverhead = 0;
233 
234   /// Target-defined identifier for constructing a frame for this function.
235   unsigned FrameConstructionID = 0;
236 
237   /// Return the number of candidates for this \p OutlinedFunction.
238   virtual unsigned getOccurrenceCount() const { return Candidates.size(); }
239 
240   /// Return the number of bytes it would take to outline this
241   /// function.
242   virtual unsigned getOutliningCost() const {
243     unsigned CallOverhead = 0;
244     for (const Candidate &C : Candidates)
245       CallOverhead += C.getCallOverhead();
246     return CallOverhead + SequenceSize + FrameOverhead;
247   }
248 
249   /// Return the size in bytes of the unoutlined sequences.
250   unsigned getNotOutlinedCost() const {
251     return getOccurrenceCount() * SequenceSize;
252   }
253 
254   /// Return the number of instructions that would be saved by outlining
255   /// this function.
256   unsigned getBenefit() const {
257     unsigned NotOutlinedCost = getNotOutlinedCost();
258     unsigned OutlinedCost = getOutliningCost();
259     return (NotOutlinedCost < OutlinedCost) ? 0
260                                             : NotOutlinedCost - OutlinedCost;
261   }
262 
263   /// Return the number of instructions in this sequence.
264   unsigned getNumInstrs() const { return Candidates[0].getLength(); }
265 
266   OutlinedFunction(std::vector<Candidate> &Candidates, unsigned SequenceSize,
267                    unsigned FrameOverhead, unsigned FrameConstructionID)
268       : Candidates(Candidates), SequenceSize(SequenceSize),
269         FrameOverhead(FrameOverhead), FrameConstructionID(FrameConstructionID) {
270     const unsigned B = getBenefit();
271     for (Candidate &C : Candidates)
272       C.Benefit = B;
273   }
274 
275   OutlinedFunction() = delete;
276   virtual ~OutlinedFunction() = default;
277 };
278 
279 /// The information necessary to create an outlined function that is matched
280 /// globally.
281 struct GlobalOutlinedFunction : public OutlinedFunction {
282   explicit GlobalOutlinedFunction(std::unique_ptr<OutlinedFunction> OF,
283                                   unsigned GlobalOccurrenceCount)
284       : OutlinedFunction(*OF), GlobalOccurrenceCount(GlobalOccurrenceCount) {}
285 
286   unsigned GlobalOccurrenceCount;
287 
288   /// Return the number of times that appear globally.
289   /// Global outlining candidate is uniquely created per each match, but this
290   /// might be erased out when it's overlapped with the previous outlining
291   /// instance.
292   unsigned getOccurrenceCount() const override {
293     assert(Candidates.size() <= 1);
294     return Candidates.empty() ? 0 : GlobalOccurrenceCount;
295   }
296 
297   /// Return the outlining cost using the global occurrence count
298   /// with the same cost as the first (unique) candidate.
299   unsigned getOutliningCost() const override {
300     assert(Candidates.size() <= 1);
301     unsigned CallOverhead =
302         Candidates.empty()
303             ? 0
304             : Candidates[0].getCallOverhead() * getOccurrenceCount();
305     return CallOverhead + SequenceSize + FrameOverhead;
306   }
307 
308   GlobalOutlinedFunction() = delete;
309   ~GlobalOutlinedFunction() = default;
310 };
311 
312 } // namespace outliner
313 } // namespace llvm
314 
315 #endif
316