LLVM 20.0.0git
Combiner.cpp
Go to the documentation of this file.
1//===-- lib/CodeGen/GlobalISel/Combiner.cpp -------------------------------===//
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// This file constains common code to combine machine functions at generic
10// level.
11//===----------------------------------------------------------------------===//
12
15#include "llvm/ADT/SetVector.h"
16#include "llvm/ADT/Statistic.h"
25#include "llvm/Support/Debug.h"
26
27#define DEBUG_TYPE "gi-combiner"
28
29using namespace llvm;
30
31STATISTIC(NumOneIteration, "Number of functions with one iteration");
32STATISTIC(NumTwoIterations, "Number of functions with two iterations");
33STATISTIC(NumThreeOrMoreIterations,
34 "Number of functions with three or more iterations");
35
36namespace llvm {
38 "GlobalISel Combiner",
39 "Control the rules which are enabled. These options all take a comma "
40 "separated list of rules to disable and may be specified by number "
41 "or number range (e.g. 1-10)."
42#ifndef NDEBUG
43 " They may also be specified by name."
44#endif
45);
46} // end namespace llvm
47
48/// This class acts as the glue that joins the CombinerHelper to the overall
49/// Combine algorithm. The CombinerHelper is intended to report the
50/// modifications it makes to the MIR to the GISelChangeObserver and the
51/// observer subclass will act on these events.
53protected:
54#ifndef NDEBUG
55 /// The instructions that have been created but we want to report once they
56 /// have their operands. This is only maintained if debug output is requested.
58#endif
60
61public:
62 static std::unique_ptr<WorkListMaintainer>
64
65 virtual ~WorkListMaintainer() = default;
66
69 for (auto *MI : CreatedInstrs) {
70 dbgs() << "Created: " << *MI;
71 }
72 CreatedInstrs.clear();
73 });
74 }
75
76 virtual void reset() = 0;
77 virtual void appliedCombine() = 0;
78};
79
80/// A configurable WorkListMaintainer implementation.
81/// The ObserverLevel determines how the WorkListMaintainer reacts to MIR
82/// changes.
83template <CombinerInfo::ObserverLevel Lvl>
84class Combiner::WorkListMaintainerImpl : public Combiner::WorkListMaintainer {
85 WorkListTy &WorkList;
87
88 // Defer handling these instructions until the combine finishes.
90
91 // Track VRegs that (might) have lost a use.
93
94public:
96 : WorkList(WorkList), MRI(MRI) {}
97
98 virtual ~WorkListMaintainerImpl() = default;
99
100 void reset() override {
101 DeferList.clear();
102 LostUses.clear();
103 }
104
105 void erasingInstr(MachineInstr &MI) override {
106 // MI will become dangling, remove it from all lists.
107 LLVM_DEBUG(dbgs() << "Erasing: " << MI; CreatedInstrs.remove(&MI));
108 WorkList.remove(&MI);
109 if constexpr (Lvl != Level::Basic) {
110 DeferList.remove(&MI);
112 }
113 }
114
115 void createdInstr(MachineInstr &MI) override {
116 LLVM_DEBUG(dbgs() << "Creating: " << MI; CreatedInstrs.insert(&MI));
117 if constexpr (Lvl == Level::Basic)
118 WorkList.insert(&MI);
119 else
120 // Defer handling newly created instructions, because they don't have
121 // operands yet. We also insert them into the WorkList in reverse
122 // order so that they will be combined top down.
123 DeferList.insert(&MI);
124 }
125
126 void changingInstr(MachineInstr &MI) override {
127 LLVM_DEBUG(dbgs() << "Changing: " << MI);
128 // Some uses might get dropped when MI is changed.
129 // For now, overapproximate by assuming all uses will be dropped.
130 // TODO: Is a more precise heuristic or manual tracking of use count
131 // decrements worth it?
132 if constexpr (Lvl != Level::Basic)
134 }
135
136 void changedInstr(MachineInstr &MI) override {
137 LLVM_DEBUG(dbgs() << "Changed: " << MI);
138 if constexpr (Lvl == Level::Basic)
139 WorkList.insert(&MI);
140 else
141 // Defer this for DCE
142 DeferList.insert(&MI);
143 }
144
145 // Only track changes during the combine and then walk the def/use-chains once
146 // the combine is finished, because:
147 // - instructions might have multiple defs during the combine.
148 // - use counts aren't accurate during the combine.
149 void appliedCombine() override {
150 if constexpr (Lvl == Level::Basic)
151 return;
152
153 // DCE deferred instructions and add them to the WorkList bottom up.
154 while (!DeferList.empty()) {
155 MachineInstr &MI = *DeferList.pop_back_val();
156 if (tryDCE(MI, MRI))
157 continue;
158
159 if constexpr (Lvl >= Level::SinglePass)
161
162 WorkList.insert(&MI);
163 }
164
165 // Handle instructions that have lost a user.
166 while (!LostUses.empty()) {
167 Register Use = LostUses.pop_back_val();
169 if (!UseMI)
170 continue;
171
172 // If DCE succeeds, UseMI's uses are added back to LostUses by
173 // erasingInstr.
174 if (tryDCE(*UseMI, MRI))
175 continue;
176
177 if constexpr (Lvl >= Level::SinglePass) {
178 // OneUse checks are relatively common, so we might be able to combine
179 // the single remaining user of this Reg.
181 WorkList.insert(&*MRI.use_instr_nodbg_begin(Use));
182
183 WorkList.insert(UseMI);
184 }
185 }
186 }
187
189 for (auto &Use : MI.explicit_uses()) {
190 if (!Use.isReg() || !Use.getReg().isVirtual())
191 continue;
192 LostUses.insert(Use.getReg());
193 }
194 }
195
197 for (auto &Def : MI.defs()) {
198 Register DefReg = Def.getReg();
199 if (!DefReg.isVirtual())
200 continue;
201 for (auto &UseMI : MRI.use_nodbg_instructions(DefReg)) {
202 WorkList.insert(&UseMI);
203 }
204 }
205 }
206};
207
208std::unique_ptr<Combiner::WorkListMaintainer>
211 switch (Lvl) {
212 case Level::Basic:
213 return std::make_unique<WorkListMaintainerImpl<Level::Basic>>(WorkList,
214 MRI);
215 case Level::DCE:
216 return std::make_unique<WorkListMaintainerImpl<Level::DCE>>(WorkList, MRI);
217 case Level::SinglePass:
218 return std::make_unique<WorkListMaintainerImpl<Level::SinglePass>>(WorkList,
219 MRI);
220 }
221 llvm_unreachable("Illegal ObserverLevel");
222}
223
227 : Builder(CSEInfo ? std::make_unique<CSEMIRBuilder>()
228 : std::make_unique<MachineIRBuilder>()),
229 WLObserver(WorkListMaintainer::create(CInfo.ObserverLvl, WorkList,
230 MF.getRegInfo())),
231 ObserverWrapper(std::make_unique<GISelObserverWrapper>()), CInfo(CInfo),
232 Observer(*ObserverWrapper), B(*Builder), MF(MF), MRI(MF.getRegInfo()),
233 KB(KB), TPC(TPC), CSEInfo(CSEInfo) {
234 (void)this->TPC; // FIXME: Remove when used.
235
236 // Setup builder.
237 B.setMF(MF);
238 if (CSEInfo)
240
241 B.setChangeObserver(*ObserverWrapper);
242}
243
244Combiner::~Combiner() = default;
245
246bool Combiner::tryDCE(MachineInstr &MI, MachineRegisterInfo &MRI) {
247 if (!isTriviallyDead(MI, MRI))
248 return false;
249 LLVM_DEBUG(dbgs() << "Dead: " << MI);
251 MI.eraseFromParent();
252 return true;
253}
254
256 // If the ISel pipeline failed, do not bother running this pass.
257 // FIXME: Should this be here or in individual combiner passes.
260 return false;
261
262 // We can't call this in the constructor because the derived class is
263 // uninitialized at that time.
264 if (!HasSetupMF) {
265 HasSetupMF = true;
266 setupMF(MF, KB);
267 }
268
269 LLVM_DEBUG(dbgs() << "Generic MI Combiner for: " << MF.getName() << '\n');
270
271 MachineOptimizationRemarkEmitter MORE(MF, /*MBFI=*/nullptr);
272
273 bool MFChanged = false;
274 bool Changed;
275
276 unsigned Iteration = 0;
277 while (true) {
278 ++Iteration;
279 LLVM_DEBUG(dbgs() << "\n\nCombiner iteration #" << Iteration << '\n');
280
281 Changed = false;
282 WorkList.clear();
283 WLObserver->reset();
284 ObserverWrapper->clearObservers();
285 if (CSEInfo)
286 ObserverWrapper->addObserver(CSEInfo);
287
288 // If Observer-based DCE is enabled, perform full DCE only before the first
289 // iteration.
291 ? CInfo.EnableFullDCE && Iteration == 1
293
294 // Collect all instructions. Do a post order traversal for basic blocks and
295 // insert with list bottom up, so while we pop_back_val, we'll traverse top
296 // down RPOT.
297 RAIIMFObsDelInstaller DelInstall(MF, *ObserverWrapper);
299 for (MachineInstr &CurMI :
301 // Erase dead insts before even adding to the list.
302 if (EnableDCE && tryDCE(CurMI, MRI))
303 continue;
304 WorkList.deferred_insert(&CurMI);
305 }
306 }
307 WorkList.finalize();
308
309 // Only notify WLObserver during actual combines
310 ObserverWrapper->addObserver(WLObserver.get());
311 // Main Loop. Process the instructions here.
312 while (!WorkList.empty()) {
313 MachineInstr &CurrInst = *WorkList.pop_back_val();
314 LLVM_DEBUG(dbgs() << "\nTry combining " << CurrInst);
315 bool AppliedCombine = tryCombineAll(CurrInst);
316 LLVM_DEBUG(WLObserver->reportFullyCreatedInstrs());
317 Changed |= AppliedCombine;
318 if (AppliedCombine)
319 WLObserver->appliedCombine();
320 }
321 MFChanged |= Changed;
322
323 if (!Changed) {
324 LLVM_DEBUG(dbgs() << "\nCombiner reached fixed-point after iteration #"
325 << Iteration << '\n');
326 break;
327 }
328 // Iterate until a fixed-point is reached if MaxIterations == 0,
329 // otherwise limit the number of iterations.
330 if (CInfo.MaxIterations && Iteration >= CInfo.MaxIterations) {
332 dbgs() << "\nCombiner reached iteration limit after iteration #"
333 << Iteration << '\n');
334 break;
335 }
336 }
337
338 if (Iteration == 1)
339 ++NumOneIteration;
340 else if (Iteration == 2)
341 ++NumTwoIterations;
342 else
343 ++NumThreeOrMoreIterations;
344
345#ifndef NDEBUG
346 if (CSEInfo) {
347 if (auto E = CSEInfo->verify()) {
348 errs() << E << '\n';
349 assert(false && "CSEInfo is not consistent. Likely missing calls to "
350 "observer on mutations.");
351 }
352 }
353#endif
354 return MFChanged;
355}
unsigned const MachineRegisterInfo * MRI
MachineInstrBuilder & UseMI
MachineBasicBlock & MBB
Provides analysis for continuously CSEing during GISel passes.
This file implements a version of MachineIRBuilder which CSEs insts within a MachineBasicBlock.
Option class for Targets to specify which operations are combined how and when.
This contains the base class for all Combiners generated by TableGen.
#define LLVM_DEBUG(...)
Definition: Debug.h:106
This contains common code to allow clients to notify changes to machine instr.
IRTranslator LLVM IR MI
This file declares the MachineIRBuilder class.
===- MachineOptimizationRemarkEmitter.h - Opt Diagnostics -*- C++ -*-—===//
This file builds on the ADT/GraphTraits.h file to build a generic graph post order iterator.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file implements a set that has insertion order iteration characteristics.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Definition: Statistic.h:166
void erasingInstr(MachineInstr &MI) override
An instruction is about to be erased.
Definition: Combiner.cpp:105
void noteLostUses(MachineInstr &MI)
Definition: Combiner.cpp:188
void changedInstr(MachineInstr &MI) override
This instruction was mutated in some way.
Definition: Combiner.cpp:136
void changingInstr(MachineInstr &MI) override
This instruction is about to be mutated in some way.
Definition: Combiner.cpp:126
WorkListMaintainerImpl(WorkListTy &WorkList, MachineRegisterInfo &MRI)
Definition: Combiner.cpp:95
void createdInstr(MachineInstr &MI) override
An instruction has been created and inserted into the function.
Definition: Combiner.cpp:115
void addUsersToWorkList(MachineInstr &MI)
Definition: Combiner.cpp:196
This class acts as the glue that joins the CombinerHelper to the overall Combine algorithm.
Definition: Combiner.cpp:52
virtual ~WorkListMaintainer()=default
SmallSetVector< const MachineInstr *, 32 > CreatedInstrs
The instructions that have been created but we want to report once they have their operands.
Definition: Combiner.cpp:57
static std::unique_ptr< WorkListMaintainer > create(Level Lvl, WorkListTy &WorkList, MachineRegisterInfo &MRI)
Definition: Combiner.cpp:209
Defines a builder that does CSE of MachineInstructions using GISelCSEInfo.
Definition: CSEMIRBuilder.h:38
GISelCSEInfo * CSEInfo
Definition: Combiner.h:78
Combiner(MachineFunction &MF, CombinerInfo &CInfo, const TargetPassConfig *TPC, GISelKnownBits *KB, GISelCSEInfo *CSEInfo=nullptr)
If CSEInfo is not null, then the Combiner will use CSEInfo as the observer and also create a CSEMIRBu...
Definition: Combiner.cpp:224
bool combineMachineInstrs()
Definition: Combiner.cpp:255
MachineRegisterInfo & MRI
Definition: Combiner.h:74
const TargetPassConfig * TPC
Definition: Combiner.h:77
virtual ~Combiner()
MachineIRBuilder & B
Definition: Combiner.h:72
GISelKnownBits * KB
Definition: Combiner.h:75
MachineFunction & MF
Definition: Combiner.h:73
CombinerInfo & CInfo
Definition: Combiner.h:70
GISelChangeObserver & Observer
Definition: Combiner.h:71
virtual bool tryCombineAll(MachineInstr &I) const =0
virtual void setupMF(MachineFunction &mf, GISelKnownBits *kb, CodeGenCoverage *covinfo=nullptr, ProfileSummaryInfo *psi=nullptr, BlockFrequencyInfo *bfi=nullptr)
Setup per-MF executor state.
The CSE Analysis object.
Definition: CSEInfo.h:70
Abstract class that contains various methods for clients to notify about changes.
Simple wrapper observer that takes several observers, and calls each one for each event.
void insert(MachineInstr *I)
Add the specified instruction to the worklist if it isn't already in it.
Definition: GISelWorkList.h:74
MachineInstr * pop_back_val()
void deferred_insert(MachineInstr *I)
Definition: GISelWorkList.h:50
bool empty() const
Definition: GISelWorkList.h:38
void remove(const MachineInstr *I)
Remove I from the worklist if it exists.
Definition: GISelWorkList.h:83
bool hasProperty(Property P) const
StringRef getName() const
getName - Return the name of the corresponding LLVM function.
const MachineFunctionProperties & getProperties() const
Get the function properties.
Helper class to build MachineInstr.
void setCSEInfo(GISelCSEInfo *Info)
void setMF(MachineFunction &MF)
void setChangeObserver(GISelChangeObserver &Observer)
Representation of each machine instruction.
Definition: MachineInstr.h:69
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
use_instr_nodbg_iterator use_instr_nodbg_begin(Register RegNo) const
bool hasOneNonDBGUser(Register RegNo) const
hasOneNonDBGUse - Return true if there is exactly one non-Debug instruction using the specified regis...
iterator_range< use_instr_nodbg_iterator > use_nodbg_instructions(Register Reg) const
Class to install both of the above.
Wrapper class representing virtual and physical registers.
Definition: Register.h:19
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
Definition: Register.h:91
bool remove(const value_type &X)
Remove an item from the set vector.
Definition: SetVector.h:188
void clear()
Completely clear the SetVector.
Definition: SetVector.h:273
bool empty() const
Determine if the SetVector is empty or not.
Definition: SetVector.h:93
bool insert(const value_type &X)
Insert a new element into the SetVector.
Definition: SetVector.h:162
value_type pop_back_val()
Definition: SetVector.h:285
A SetVector that performs no allocations if smaller than a certain size.
Definition: SetVector.h:370
Target-Independent Code Generator Pass Configuration Options.
A Use represents the edge between a Value definition and its users.
Definition: Use.h:43
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
void salvageDebugInfo(const MachineRegisterInfo &MRI, MachineInstr &MI)
Assuming the instruction MI is going to be deleted, attempt to salvage debug users of MI by writing t...
Definition: Utils.cpp:1656
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
Definition: STLExtras.h:657
iterator_range< po_iterator< T > > post_order(const T &G)
auto reverse(ContainerTy &&C)
Definition: STLExtras.h:420
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
cl::OptionCategory GICombinerOptionCategory("GlobalISel Combiner", "Control the rules which are enabled. These options all take a comma " "separated list of rules to disable and may be specified by number " "or number range (e.g. 1-10)." " They may also be specified by name.")
bool isTriviallyDead(const MachineInstr &MI, const MachineRegisterInfo &MRI)
Check whether an instruction MI is dead: it only defines dead virtual registers, and doesn't have oth...
Definition: Utils.cpp:222
Implement std::hash so that hash_code can be used in STL containers.
Definition: BitVector.h:858
#define MORE()
Definition: regcomp.c:252
#define NDEBUG
Definition: regutils.h:48
unsigned MaxIterations
The maximum number of times the Combiner will iterate over the MachineFunction.
Definition: CombinerInfo.h:55
ObserverLevel ObserverLvl
Select how the Combiner acts on MIR changes.
Definition: CombinerInfo.h:75
bool EnableFullDCE
Whether dead code elimination is performed before each Combiner iteration.
Definition: CombinerInfo.h:80
@ DCE
Enables Observer-based detection of dead instructions.