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