Coverage Report

Created: 2024-01-17 10:31

/src/llvm-project/llvm/lib/CodeGen/RegAllocEvictionAdvisor.h
Line
Count
Source (jump to first uncovered line)
1
//===- RegAllocEvictionAdvisor.h - Interference resolution ------*- 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
#ifndef LLVM_CODEGEN_REGALLOCEVICTIONADVISOR_H
10
#define LLVM_CODEGEN_REGALLOCEVICTIONADVISOR_H
11
12
#include "llvm/ADT/ArrayRef.h"
13
#include "llvm/ADT/SmallSet.h"
14
#include "llvm/ADT/StringRef.h"
15
#include "llvm/CodeGen/Register.h"
16
#include "llvm/Config/llvm-config.h"
17
#include "llvm/MC/MCRegister.h"
18
#include "llvm/Pass.h"
19
20
namespace llvm {
21
class AllocationOrder;
22
class LiveInterval;
23
class LiveIntervals;
24
class LiveRegMatrix;
25
class MachineFunction;
26
class MachineRegisterInfo;
27
class RegisterClassInfo;
28
class TargetRegisterInfo;
29
class VirtRegMap;
30
31
using SmallVirtRegSet = SmallSet<Register, 16>;
32
33
// Live ranges pass through a number of stages as we try to allocate them.
34
// Some of the stages may also create new live ranges:
35
//
36
// - Region splitting.
37
// - Per-block splitting.
38
// - Local splitting.
39
// - Spilling.
40
//
41
// Ranges produced by one of the stages skip the previous stages when they are
42
// dequeued. This improves performance because we can skip interference checks
43
// that are unlikely to give any results. It also guarantees that the live
44
// range splitting algorithm terminates, something that is otherwise hard to
45
// ensure.
46
enum LiveRangeStage {
47
  /// Newly created live range that has never been queued.
48
  RS_New,
49
50
  /// Only attempt assignment and eviction. Then requeue as RS_Split.
51
  RS_Assign,
52
53
  /// Attempt live range splitting if assignment is impossible.
54
  RS_Split,
55
56
  /// Attempt more aggressive live range splitting that is guaranteed to make
57
  /// progress.  This is used for split products that may not be making
58
  /// progress.
59
  RS_Split2,
60
61
  /// Live range will be spilled.  No more splitting will be attempted.
62
  RS_Spill,
63
64
  /// Live range is in memory. Because of other evictions, it might get moved
65
  /// in a register in the end.
66
  RS_Memory,
67
68
  /// There is nothing more we can do to this live range.  Abort compilation
69
  /// if it can't be assigned.
70
  RS_Done
71
};
72
73
/// Cost of evicting interference - used by default advisor, and the eviction
74
/// chain heuristic in RegAllocGreedy.
75
// FIXME: this can be probably made an implementation detail of the default
76
// advisor, if the eviction chain logic can be refactored.
77
struct EvictionCost {
78
  unsigned BrokenHints = 0; ///< Total number of broken hints.
79
  float MaxWeight = 0;      ///< Maximum spill weight evicted.
80
81
13.7M
  EvictionCost() = default;
82
83
2.83M
  bool isMax() const { return BrokenHints == ~0u; }
84
85
736k
  void setMax() { BrokenHints = ~0u; }
86
87
136k
  void setBrokenHints(unsigned NHints) { BrokenHints = NHints; }
88
89
11.2M
  bool operator<(const EvictionCost &O) const {
90
11.2M
    return std::tie(BrokenHints, MaxWeight) <
91
11.2M
           std::tie(O.BrokenHints, O.MaxWeight);
92
11.2M
  }
93
};
94
95
/// Interface to the eviction advisor, which is responsible for making a
96
/// decision as to which live ranges should be evicted (if any).
97
class RAGreedy;
98
class RegAllocEvictionAdvisor {
99
public:
100
  RegAllocEvictionAdvisor(const RegAllocEvictionAdvisor &) = delete;
101
  RegAllocEvictionAdvisor(RegAllocEvictionAdvisor &&) = delete;
102
77.6k
  virtual ~RegAllocEvictionAdvisor() = default;
103
104
  /// Find a physical register that can be freed by evicting the FixedRegisters,
105
  /// or return NoRegister. The eviction decision is assumed to be correct (i.e.
106
  /// no fixed live ranges are evicted) and profitable.
107
  virtual MCRegister tryFindEvictionCandidate(
108
      const LiveInterval &VirtReg, const AllocationOrder &Order,
109
      uint8_t CostPerUseLimit, const SmallVirtRegSet &FixedRegisters) const = 0;
110
111
  /// Find out if we can evict the live ranges occupying the given PhysReg,
112
  /// which is a hint (preferred register) for VirtReg.
113
  virtual bool
114
  canEvictHintInterference(const LiveInterval &VirtReg, MCRegister PhysReg,
115
                           const SmallVirtRegSet &FixedRegisters) const = 0;
116
117
  /// Returns true if the given \p PhysReg is a callee saved register and has
118
  /// not been used for allocation yet.
119
  bool isUnusedCalleeSavedReg(MCRegister PhysReg) const;
120
121
protected:
122
  RegAllocEvictionAdvisor(const MachineFunction &MF, const RAGreedy &RA);
123
124
  bool canReassign(const LiveInterval &VirtReg, MCRegister FromReg) const;
125
126
  // Get the upper limit of elements in the given Order we need to analize.
127
  // TODO: is this heuristic,  we could consider learning it.
128
  std::optional<unsigned> getOrderLimit(const LiveInterval &VirtReg,
129
                                        const AllocationOrder &Order,
130
                                        unsigned CostPerUseLimit) const;
131
132
  // Determine if it's worth trying to allocate this reg, given the
133
  // CostPerUseLimit
134
  // TODO: this is a heuristic component we could consider learning, too.
135
  bool canAllocatePhysReg(unsigned CostPerUseLimit, MCRegister PhysReg) const;
136
137
  const MachineFunction &MF;
138
  const RAGreedy &RA;
139
  LiveRegMatrix *const Matrix;
140
  LiveIntervals *const LIS;
141
  VirtRegMap *const VRM;
142
  MachineRegisterInfo *const MRI;
143
  const TargetRegisterInfo *const TRI;
144
  const RegisterClassInfo &RegClassInfo;
145
  const ArrayRef<uint8_t> RegCosts;
146
147
  /// Run or not the local reassignment heuristic. This information is
148
  /// obtained from the TargetSubtargetInfo.
149
  const bool EnableLocalReassign;
150
};
151
152
/// ImmutableAnalysis abstraction for fetching the Eviction Advisor. We model it
153
/// as an analysis to decouple the user from the implementation insofar as
154
/// dependencies on other analyses goes. The motivation for it being an
155
/// immutable pass is twofold:
156
/// - in the ML implementation case, the evaluator is stateless but (especially
157
/// in the development mode) expensive to set up. With an immutable pass, we set
158
/// it up once.
159
/// - in the 'development' mode ML case, we want to capture the training log
160
/// during allocation (this is a log of features encountered and decisions
161
/// made), and then measure a score, potentially a few steps after allocation
162
/// completes. So we need the properties of an immutable pass to keep the logger
163
/// state around until we can make that measurement.
164
///
165
/// Because we need to offer additional services in 'development' mode, the
166
/// implementations of this analysis need to implement RTTI support.
167
class RegAllocEvictionAdvisorAnalysis : public ImmutablePass {
168
public:
169
  enum class AdvisorMode : int { Default, Release, Development };
170
171
  RegAllocEvictionAdvisorAnalysis(AdvisorMode Mode)
172
33.1k
      : ImmutablePass(ID), Mode(Mode){};
173
  static char ID;
174
175
  /// Get an advisor for the given context (i.e. machine function, etc)
176
  virtual std::unique_ptr<RegAllocEvictionAdvisor>
177
  getAdvisor(const MachineFunction &MF, const RAGreedy &RA) = 0;
178
0
  AdvisorMode getAdvisorMode() const { return Mode; }
179
  virtual void logRewardIfNeeded(const MachineFunction &MF,
180
0
                                 llvm::function_ref<float()> GetReward){};
181
182
protected:
183
  // This analysis preserves everything, and subclasses may have additional
184
  // requirements.
185
33.1k
  void getAnalysisUsage(AnalysisUsage &AU) const override {
186
33.1k
    AU.setPreservesAll();
187
33.1k
  }
188
189
private:
190
  StringRef getPassName() const override;
191
  const AdvisorMode Mode;
192
};
193
194
/// Specialization for the API used by the analysis infrastructure to create
195
/// an instance of the eviction advisor.
196
template <> Pass *callDefaultCtor<RegAllocEvictionAdvisorAnalysis>();
197
198
RegAllocEvictionAdvisorAnalysis *createReleaseModeAdvisor();
199
200
RegAllocEvictionAdvisorAnalysis *createDevelopmentModeAdvisor();
201
202
// TODO: move to RegAllocEvictionAdvisor.cpp when we move implementation
203
// out of RegAllocGreedy.cpp
204
class DefaultEvictionAdvisor : public RegAllocEvictionAdvisor {
205
public:
206
  DefaultEvictionAdvisor(const MachineFunction &MF, const RAGreedy &RA)
207
77.6k
      : RegAllocEvictionAdvisor(MF, RA) {}
208
209
private:
210
  MCRegister tryFindEvictionCandidate(const LiveInterval &,
211
                                      const AllocationOrder &, uint8_t,
212
                                      const SmallVirtRegSet &) const override;
213
  bool canEvictHintInterference(const LiveInterval &, MCRegister,
214
                                const SmallVirtRegSet &) const override;
215
  bool canEvictInterferenceBasedOnCost(const LiveInterval &, MCRegister, bool,
216
                                       EvictionCost &,
217
                                       const SmallVirtRegSet &) const;
218
  bool shouldEvict(const LiveInterval &A, bool, const LiveInterval &B,
219
                   bool) const;
220
};
221
} // namespace llvm
222
223
#endif // LLVM_CODEGEN_REGALLOCEVICTIONADVISOR_H