| 1 | //==- RegAllocGreedy.h ------- greedy register allocator ----------*-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 | // This file defines the RAGreedy function pass for register allocation in |
| 9 | // optimized builds. |
| 10 | //===----------------------------------------------------------------------===// |
| 11 | |
| 12 | #ifndef LLVM_CODEGEN_REGALLOCGREEDY_H_ |
| 13 | #define LLVM_CODEGEN_REGALLOCGREEDY_H_ |
| 14 | |
| 15 | #include "InterferenceCache.h" |
| 16 | #include "RegAllocBase.h" |
| 17 | #include "SplitKit.h" |
| 18 | #include "llvm/ADT/ArrayRef.h" |
| 19 | #include "llvm/ADT/BitVector.h" |
| 20 | #include "llvm/ADT/IndexedMap.h" |
| 21 | #include "llvm/ADT/SetVector.h" |
| 22 | #include "llvm/ADT/SmallVector.h" |
| 23 | #include "llvm/ADT/StringRef.h" |
| 24 | #include "llvm/CodeGen/CalcSpillWeights.h" |
| 25 | #include "llvm/CodeGen/LiveDebugVariables.h" |
| 26 | #include "llvm/CodeGen/LiveInterval.h" |
| 27 | #include "llvm/CodeGen/LiveRangeEdit.h" |
| 28 | #include "llvm/CodeGen/LiveStacks.h" |
| 29 | #include "llvm/CodeGen/MachineFunction.h" |
| 30 | #include "llvm/CodeGen/RegAllocEvictionAdvisor.h" |
| 31 | #include "llvm/CodeGen/RegAllocPriorityAdvisor.h" |
| 32 | #include "llvm/CodeGen/RegisterClassInfo.h" |
| 33 | #include "llvm/CodeGen/SpillPlacement.h" |
| 34 | #include "llvm/CodeGen/Spiller.h" |
| 35 | #include "llvm/CodeGen/TargetRegisterInfo.h" |
| 36 | #include <algorithm> |
| 37 | #include <cstdint> |
| 38 | #include <memory> |
| 39 | #include <queue> |
| 40 | #include <utility> |
| 41 | |
| 42 | namespace llvm { |
| 43 | class AllocationOrder; |
| 44 | class AnalysisUsage; |
| 45 | class EdgeBundles; |
| 46 | class LiveDebugVariablesWrapperLegacy; |
| 47 | class LiveIntervals; |
| 48 | class LiveRegMatrix; |
| 49 | class MachineBasicBlock; |
| 50 | class MachineBlockFrequencyInfo; |
| 51 | class MachineDominatorTree; |
| 52 | class MachineLoop; |
| 53 | class MachineLoopInfo; |
| 54 | class ; |
| 55 | class ; |
| 56 | class SlotIndexes; |
| 57 | class TargetInstrInfo; |
| 58 | class VirtRegMap; |
| 59 | |
| 60 | class LLVM_LIBRARY_VISIBILITY RAGreedy : public RegAllocBase, |
| 61 | private LiveRangeEdit::Delegate { |
| 62 | public: |
| 63 | struct RequiredAnalyses; |
| 64 | |
| 65 | // Interface to eviction advisers |
| 66 | /// Track allocation stage and eviction loop prevention during allocation. |
| 67 | class final { |
| 68 | // RegInfo - Keep additional information about each live range. |
| 69 | struct { |
| 70 | LiveRangeStage = RS_New; |
| 71 | |
| 72 | // Cascade - Eviction loop prevention. See |
| 73 | // canEvictInterferenceBasedOnCost(). |
| 74 | unsigned = 0; |
| 75 | |
| 76 | () = default; |
| 77 | }; |
| 78 | |
| 79 | IndexedMap<RegInfo, VirtReg2IndexFunctor> ; |
| 80 | unsigned = 1; |
| 81 | |
| 82 | public: |
| 83 | () {} |
| 84 | (const ExtraRegInfo &) = delete; |
| 85 | |
| 86 | LiveRangeStage (Register Reg) const { return Info[Reg].Stage; } |
| 87 | |
| 88 | LiveRangeStage (const LiveInterval &VirtReg) const { |
| 89 | return getStage(Reg: VirtReg.reg()); |
| 90 | } |
| 91 | |
| 92 | void (Register Reg, LiveRangeStage Stage) { |
| 93 | Info.grow(n: Reg.id()); |
| 94 | Info[Reg].Stage = Stage; |
| 95 | } |
| 96 | |
| 97 | void (const LiveInterval &VirtReg, LiveRangeStage Stage) { |
| 98 | setStage(Reg: VirtReg.reg(), Stage); |
| 99 | } |
| 100 | |
| 101 | /// Return the current stage of the register, if present, otherwise |
| 102 | /// initialize it and return that. |
| 103 | LiveRangeStage (Register Reg) { |
| 104 | Info.grow(n: Reg.id()); |
| 105 | return getStage(Reg); |
| 106 | } |
| 107 | |
| 108 | unsigned (Register Reg) const { return Info[Reg].Cascade; } |
| 109 | |
| 110 | void (Register Reg, unsigned Cascade) { |
| 111 | Info.grow(n: Reg.id()); |
| 112 | Info[Reg].Cascade = Cascade; |
| 113 | } |
| 114 | |
| 115 | unsigned (Register Reg) { |
| 116 | unsigned Cascade = getCascade(Reg); |
| 117 | if (!Cascade) { |
| 118 | Cascade = NextCascade++; |
| 119 | setCascade(Reg, Cascade); |
| 120 | } |
| 121 | return Cascade; |
| 122 | } |
| 123 | |
| 124 | unsigned (Register Reg) const { |
| 125 | unsigned Cascade = getCascade(Reg); |
| 126 | if (!Cascade) |
| 127 | Cascade = NextCascade; |
| 128 | return Cascade; |
| 129 | } |
| 130 | |
| 131 | template <typename Iterator> |
| 132 | void (Iterator Begin, Iterator End, LiveRangeStage NewStage) { |
| 133 | for (; Begin != End; ++Begin) { |
| 134 | Register Reg = *Begin; |
| 135 | Info.grow(n: Reg.id()); |
| 136 | if (Info[Reg].Stage == RS_New) |
| 137 | Info[Reg].Stage = NewStage; |
| 138 | } |
| 139 | } |
| 140 | void (Register New, Register Old); |
| 141 | }; |
| 142 | |
| 143 | LiveRegMatrix *getInterferenceMatrix() const { return Matrix; } |
| 144 | LiveIntervals *getLiveIntervals() const { return LIS; } |
| 145 | VirtRegMap *getVirtRegMap() const { return VRM; } |
| 146 | const RegisterClassInfo &getRegClassInfo() const { return RegClassInfo; } |
| 147 | const ExtraRegInfo &() const { return *ExtraInfo; } |
| 148 | size_t getQueueSize() const { return Queue.size(); } |
| 149 | // end (interface to eviction advisers) |
| 150 | |
| 151 | // Interface to priority advisers |
| 152 | bool getRegClassPriorityTrumpsGlobalness() const { |
| 153 | return RegClassPriorityTrumpsGlobalness; |
| 154 | } |
| 155 | bool getReverseLocalAssignment() const { return ReverseLocalAssignment; } |
| 156 | // end (interface to priority advisers) |
| 157 | |
| 158 | private: |
| 159 | // Convenient shortcuts. |
| 160 | using PQueue = std::priority_queue<std::pair<unsigned, unsigned>>; |
| 161 | using SmallLISet = SmallSetVector<const LiveInterval *, 4>; |
| 162 | |
| 163 | // We need to track all tentative recolorings so we can roll back any |
| 164 | // successful and unsuccessful recoloring attempts. |
| 165 | using RecoloringStack = |
| 166 | SmallVector<std::pair<const LiveInterval *, MCRegister>, 8>; |
| 167 | |
| 168 | // context |
| 169 | MachineFunction *MF = nullptr; |
| 170 | |
| 171 | // Shortcuts to some useful interface. |
| 172 | const TargetInstrInfo *TII = nullptr; |
| 173 | |
| 174 | // analyses |
| 175 | SlotIndexes *Indexes = nullptr; |
| 176 | MachineBlockFrequencyInfo *MBFI = nullptr; |
| 177 | MachineDominatorTree *DomTree = nullptr; |
| 178 | MachineLoopInfo *Loops = nullptr; |
| 179 | MachineOptimizationRemarkEmitter *ORE = nullptr; |
| 180 | EdgeBundles *Bundles = nullptr; |
| 181 | SpillPlacement *SpillPlacer = nullptr; |
| 182 | LiveDebugVariables *DebugVars = nullptr; |
| 183 | LiveStacks *LSS = nullptr; // Used by InlineSpiller |
| 184 | // Proxy for the advisors |
| 185 | RegAllocEvictionAdvisorProvider *EvictProvider = nullptr; |
| 186 | RegAllocPriorityAdvisorProvider *PriorityProvider = nullptr; |
| 187 | |
| 188 | // state |
| 189 | std::unique_ptr<Spiller> SpillerInstance; |
| 190 | PQueue Queue; |
| 191 | std::unique_ptr<VirtRegAuxInfo> VRAI; |
| 192 | std::optional<ExtraRegInfo> ; |
| 193 | std::unique_ptr<RegAllocEvictionAdvisor> EvictAdvisor; |
| 194 | |
| 195 | std::unique_ptr<RegAllocPriorityAdvisor> PriorityAdvisor; |
| 196 | |
| 197 | // Enum CutOffStage to keep a track whether the register allocation failed |
| 198 | // because of the cutoffs encountered in last chance recoloring. |
| 199 | // Note: This is used as bitmask. New value should be next power of 2. |
| 200 | enum CutOffStage { |
| 201 | // No cutoffs encountered |
| 202 | CO_None = 0, |
| 203 | |
| 204 | // lcr-max-depth cutoff encountered |
| 205 | CO_Depth = 1, |
| 206 | |
| 207 | // lcr-max-interf cutoff encountered |
| 208 | CO_Interf = 2 |
| 209 | }; |
| 210 | |
| 211 | uint8_t CutOffInfo = CutOffStage::CO_None; |
| 212 | |
| 213 | #ifndef NDEBUG |
| 214 | static const char *const StageName[]; |
| 215 | #endif |
| 216 | |
| 217 | // splitting state. |
| 218 | std::unique_ptr<SplitAnalysis> SA; |
| 219 | std::unique_ptr<SplitEditor> SE; |
| 220 | |
| 221 | /// Cached per-block interference maps |
| 222 | InterferenceCache IntfCache; |
| 223 | |
| 224 | /// All basic blocks where the current register has uses. |
| 225 | SmallVector<SpillPlacement::BlockConstraint, 8> SplitConstraints; |
| 226 | |
| 227 | /// Global live range splitting candidate info. |
| 228 | struct GlobalSplitCandidate { |
| 229 | // Register intended for assignment, or 0. |
| 230 | MCRegister PhysReg; |
| 231 | |
| 232 | // SplitKit interval index for this candidate. |
| 233 | unsigned IntvIdx; |
| 234 | |
| 235 | // Interference for PhysReg. |
| 236 | InterferenceCache::Cursor Intf; |
| 237 | |
| 238 | // Bundles where this candidate should be live. |
| 239 | BitVector LiveBundles; |
| 240 | SmallVector<unsigned, 8> ActiveBlocks; |
| 241 | |
| 242 | void reset(InterferenceCache &Cache, MCRegister Reg) { |
| 243 | PhysReg = Reg; |
| 244 | IntvIdx = 0; |
| 245 | Intf.setPhysReg(Cache, PhysReg: Reg); |
| 246 | LiveBundles.clear(); |
| 247 | ActiveBlocks.clear(); |
| 248 | } |
| 249 | |
| 250 | // Set B[I] = C for every live bundle where B[I] was NoCand. |
| 251 | unsigned getBundles(SmallVectorImpl<unsigned> &B, unsigned C) { |
| 252 | unsigned Count = 0; |
| 253 | for (unsigned I : LiveBundles.set_bits()) |
| 254 | if (B[I] == NoCand) { |
| 255 | B[I] = C; |
| 256 | Count++; |
| 257 | } |
| 258 | return Count; |
| 259 | } |
| 260 | }; |
| 261 | |
| 262 | /// Candidate info for each PhysReg in AllocationOrder. |
| 263 | /// This vector never shrinks, but grows to the size of the largest register |
| 264 | /// class. |
| 265 | SmallVector<GlobalSplitCandidate, 32> GlobalCand; |
| 266 | |
| 267 | enum : unsigned { NoCand = ~0u }; |
| 268 | |
| 269 | /// Candidate map. Each edge bundle is assigned to a GlobalCand entry, or to |
| 270 | /// NoCand which indicates the stack interval. |
| 271 | SmallVector<unsigned, 32> BundleCand; |
| 272 | |
| 273 | /// Callee-save register cost, calculated once per machine function. |
| 274 | BlockFrequency CSRCost; |
| 275 | |
| 276 | /// Set of broken hints that may be reconciled later because of eviction. |
| 277 | SmallSetVector<const LiveInterval *, 8> SetOfBrokenHints; |
| 278 | |
| 279 | /// The register cost values. This list will be recreated for each Machine |
| 280 | /// Function |
| 281 | ArrayRef<uint8_t> RegCosts; |
| 282 | |
| 283 | /// Flags for the live range priority calculation, determined once per |
| 284 | /// machine function. |
| 285 | bool RegClassPriorityTrumpsGlobalness = false; |
| 286 | |
| 287 | bool ReverseLocalAssignment = false; |
| 288 | |
| 289 | public: |
| 290 | RAGreedy(RequiredAnalyses &Analyses, const RegAllocFilterFunc F = nullptr); |
| 291 | |
| 292 | Spiller &spiller() override { return *SpillerInstance; } |
| 293 | void enqueueImpl(const LiveInterval *LI) override; |
| 294 | const LiveInterval *dequeue() override; |
| 295 | MCRegister selectOrSplit(const LiveInterval &, |
| 296 | SmallVectorImpl<Register> &) override; |
| 297 | void aboutToRemoveInterval(const LiveInterval &) override; |
| 298 | |
| 299 | /// Perform register allocation. |
| 300 | bool run(MachineFunction &mf); |
| 301 | |
| 302 | void releaseMemory(); |
| 303 | |
| 304 | private: |
| 305 | MCRegister selectOrSplitImpl(const LiveInterval &, |
| 306 | SmallVectorImpl<Register> &, SmallVirtRegSet &, |
| 307 | RecoloringStack &, unsigned = 0); |
| 308 | |
| 309 | bool LRE_CanEraseVirtReg(Register) override; |
| 310 | void LRE_WillShrinkVirtReg(Register) override; |
| 311 | void LRE_DidCloneVirtReg(Register, Register) override; |
| 312 | void enqueue(PQueue &CurQueue, const LiveInterval *LI); |
| 313 | const LiveInterval *dequeue(PQueue &CurQueue); |
| 314 | |
| 315 | bool hasVirtRegAlloc(); |
| 316 | BlockFrequency calcSpillCost(); |
| 317 | bool addSplitConstraints(InterferenceCache::Cursor, BlockFrequency &); |
| 318 | bool addThroughConstraints(InterferenceCache::Cursor, ArrayRef<unsigned>); |
| 319 | bool growRegion(GlobalSplitCandidate &Cand); |
| 320 | BlockFrequency calcGlobalSplitCost(GlobalSplitCandidate &, |
| 321 | const AllocationOrder &Order); |
| 322 | bool calcCompactRegion(GlobalSplitCandidate &); |
| 323 | void splitAroundRegion(LiveRangeEdit &, ArrayRef<unsigned>); |
| 324 | void calcGapWeights(MCRegister, SmallVectorImpl<float> &); |
| 325 | void evictInterference(const LiveInterval &, MCRegister, |
| 326 | SmallVectorImpl<Register> &); |
| 327 | bool mayRecolorAllInterferences(MCRegister PhysReg, |
| 328 | const LiveInterval &VirtReg, |
| 329 | SmallLISet &RecoloringCandidates, |
| 330 | const SmallVirtRegSet &FixedRegisters); |
| 331 | |
| 332 | MCRegister tryAssign(const LiveInterval &, AllocationOrder &, |
| 333 | SmallVectorImpl<Register> &, const SmallVirtRegSet &); |
| 334 | MCRegister tryEvict(const LiveInterval &, AllocationOrder &, |
| 335 | SmallVectorImpl<Register> &, uint8_t, |
| 336 | const SmallVirtRegSet &); |
| 337 | MCRegister tryRegionSplit(const LiveInterval &, AllocationOrder &, |
| 338 | SmallVectorImpl<Register> &); |
| 339 | /// Calculate cost of region splitting around the specified register. |
| 340 | unsigned calculateRegionSplitCostAroundReg(MCPhysReg PhysReg, |
| 341 | AllocationOrder &Order, |
| 342 | BlockFrequency &BestCost, |
| 343 | unsigned &NumCands, |
| 344 | unsigned &BestCand); |
| 345 | /// Calculate cost of region splitting. |
| 346 | unsigned calculateRegionSplitCost(const LiveInterval &VirtReg, |
| 347 | AllocationOrder &Order, |
| 348 | BlockFrequency &BestCost, |
| 349 | unsigned &NumCands, bool IgnoreCSR); |
| 350 | /// Perform region splitting. |
| 351 | MCRegister doRegionSplit(const LiveInterval &VirtReg, unsigned BestCand, |
| 352 | bool HasCompact, |
| 353 | SmallVectorImpl<Register> &NewVRegs); |
| 354 | /// Try to split VirtReg around physical Hint register. |
| 355 | bool trySplitAroundHintReg(MCPhysReg Hint, const LiveInterval &VirtReg, |
| 356 | SmallVectorImpl<Register> &NewVRegs, |
| 357 | AllocationOrder &Order); |
| 358 | /// Check other options before using a callee-saved register for the first |
| 359 | /// time. |
| 360 | MCRegister tryAssignCSRFirstTime(const LiveInterval &VirtReg, |
| 361 | AllocationOrder &Order, MCRegister PhysReg, |
| 362 | uint8_t &CostPerUseLimit, |
| 363 | SmallVectorImpl<Register> &NewVRegs); |
| 364 | void initializeCSRCost(); |
| 365 | MCRegister tryBlockSplit(const LiveInterval &, AllocationOrder &, |
| 366 | SmallVectorImpl<Register> &); |
| 367 | MCRegister tryInstructionSplit(const LiveInterval &, AllocationOrder &, |
| 368 | SmallVectorImpl<Register> &); |
| 369 | MCRegister tryLocalSplit(const LiveInterval &, AllocationOrder &, |
| 370 | SmallVectorImpl<Register> &); |
| 371 | MCRegister trySplit(const LiveInterval &, AllocationOrder &, |
| 372 | SmallVectorImpl<Register> &, const SmallVirtRegSet &); |
| 373 | MCRegister tryLastChanceRecoloring(const LiveInterval &, AllocationOrder &, |
| 374 | SmallVectorImpl<Register> &, |
| 375 | SmallVirtRegSet &, RecoloringStack &, |
| 376 | unsigned); |
| 377 | bool tryRecoloringCandidates(PQueue &, SmallVectorImpl<Register> &, |
| 378 | SmallVirtRegSet &, RecoloringStack &, unsigned); |
| 379 | void tryHintRecoloring(const LiveInterval &); |
| 380 | void tryHintsRecoloring(); |
| 381 | |
| 382 | /// Model the information carried by one end of a copy. |
| 383 | struct HintInfo { |
| 384 | /// The frequency of the copy. |
| 385 | BlockFrequency Freq; |
| 386 | /// The virtual register or physical register. |
| 387 | Register Reg; |
| 388 | /// Its currently assigned register. |
| 389 | /// In case of a physical register Reg == PhysReg. |
| 390 | MCRegister PhysReg; |
| 391 | |
| 392 | HintInfo(BlockFrequency Freq, Register Reg, MCRegister PhysReg) |
| 393 | : Freq(Freq), Reg(Reg), PhysReg(PhysReg) {} |
| 394 | }; |
| 395 | using HintsInfo = SmallVector<HintInfo, 4>; |
| 396 | |
| 397 | BlockFrequency getBrokenHintFreq(const HintsInfo &, MCRegister); |
| 398 | void collectHintInfo(Register, HintsInfo &); |
| 399 | |
| 400 | /// Greedy RA statistic to remark. |
| 401 | struct RAGreedyStats { |
| 402 | unsigned Reloads = 0; |
| 403 | unsigned FoldedReloads = 0; |
| 404 | unsigned ZeroCostFoldedReloads = 0; |
| 405 | unsigned Spills = 0; |
| 406 | unsigned FoldedSpills = 0; |
| 407 | unsigned Copies = 0; |
| 408 | float ReloadsCost = 0.0f; |
| 409 | float FoldedReloadsCost = 0.0f; |
| 410 | float SpillsCost = 0.0f; |
| 411 | float FoldedSpillsCost = 0.0f; |
| 412 | float CopiesCost = 0.0f; |
| 413 | |
| 414 | bool isEmpty() { |
| 415 | return !(Reloads || FoldedReloads || Spills || FoldedSpills || |
| 416 | ZeroCostFoldedReloads || Copies); |
| 417 | } |
| 418 | |
| 419 | void add(const RAGreedyStats &other) { |
| 420 | Reloads += other.Reloads; |
| 421 | FoldedReloads += other.FoldedReloads; |
| 422 | ZeroCostFoldedReloads += other.ZeroCostFoldedReloads; |
| 423 | Spills += other.Spills; |
| 424 | FoldedSpills += other.FoldedSpills; |
| 425 | Copies += other.Copies; |
| 426 | ReloadsCost += other.ReloadsCost; |
| 427 | FoldedReloadsCost += other.FoldedReloadsCost; |
| 428 | SpillsCost += other.SpillsCost; |
| 429 | FoldedSpillsCost += other.FoldedSpillsCost; |
| 430 | CopiesCost += other.CopiesCost; |
| 431 | } |
| 432 | |
| 433 | void (MachineOptimizationRemarkMissed &R); |
| 434 | }; |
| 435 | |
| 436 | /// Compute statistic for a basic block. |
| 437 | RAGreedyStats computeStats(MachineBasicBlock &MBB); |
| 438 | |
| 439 | /// Compute and report statistic through a remark. |
| 440 | RAGreedyStats reportStats(MachineLoop *L); |
| 441 | |
| 442 | /// Report the statistic for each loop. |
| 443 | void reportStats(); |
| 444 | }; |
| 445 | } // namespace llvm |
| 446 | #endif // #ifndef LLVM_CODEGEN_REGALLOCGREEDY_H_ |
| 447 | |