LLVM 22.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 VT(VT), 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.
258 if (MF.getProperties().hasFailedISel())
259 return false;
260
261 // We can't call this in the constructor because the derived class is
262 // uninitialized at that time.
263 if (!HasSetupMF) {
264 HasSetupMF = true;
265 setupMF(MF, VT);
266 }
267
268 LLVM_DEBUG(dbgs() << "Generic MI Combiner for: " << MF.getName() << '\n');
269
270 MachineOptimizationRemarkEmitter MORE(MF, /*MBFI=*/nullptr);
271
272 bool MFChanged = false;
273 bool Changed;
274
275 unsigned Iteration = 0;
276 while (true) {
277 ++Iteration;
278 LLVM_DEBUG(dbgs() << "\n\nCombiner iteration #" << Iteration << '\n');
279
280 Changed = false;
281 WorkList.clear();
282 WLObserver->reset();
283 ObserverWrapper->clearObservers();
284 if (CSEInfo)
285 ObserverWrapper->addObserver(CSEInfo);
286
287 // If Observer-based DCE is enabled, perform full DCE only before the first
288 // iteration.
290 ? CInfo.EnableFullDCE && Iteration == 1
292
293 // Collect all instructions. Do a post order traversal for basic blocks and
294 // insert with list bottom up, so while we pop_back_val, we'll traverse top
295 // down RPOT.
296 RAIIMFObsDelInstaller DelInstall(MF, *ObserverWrapper);
298 for (MachineInstr &CurMI :
300 // Erase dead insts before even adding to the list.
301 if (EnableDCE && tryDCE(CurMI, MRI))
302 continue;
303 WorkList.deferred_insert(&CurMI);
304 }
305 }
306 WorkList.finalize();
307
308 // Only notify WLObserver during actual combines
309 ObserverWrapper->addObserver(WLObserver.get());
310 // Main Loop. Process the instructions here.
311 while (!WorkList.empty()) {
312 MachineInstr &CurrInst = *WorkList.pop_back_val();
313 LLVM_DEBUG(dbgs() << "\nTry combining " << CurrInst);
314 bool AppliedCombine = tryCombineAll(CurrInst);
315 LLVM_DEBUG(WLObserver->reportFullyCreatedInstrs());
316 Changed |= AppliedCombine;
317 if (AppliedCombine)
318 WLObserver->appliedCombine();
319 }
320 MFChanged |= Changed;
321
322 if (!Changed) {
323 LLVM_DEBUG(dbgs() << "\nCombiner reached fixed-point after iteration #"
324 << Iteration << '\n');
325 break;
326 }
327 // Iterate until a fixed-point is reached if MaxIterations == 0,
328 // otherwise limit the number of iterations.
329 if (CInfo.MaxIterations && Iteration >= CInfo.MaxIterations) {
331 dbgs() << "\nCombiner reached iteration limit after iteration #"
332 << Iteration << '\n');
333 break;
334 }
335 }
336
337 if (Iteration == 1)
338 ++NumOneIteration;
339 else if (Iteration == 2)
340 ++NumTwoIterations;
341 else
342 ++NumThreeOrMoreIterations;
343
344#ifndef NDEBUG
345 if (CSEInfo) {
346 if (auto E = CSEInfo->verify()) {
347 errs() << E << '\n';
348 assert(false && "CSEInfo is not consistent. Likely missing calls to "
349 "observer on mutations.");
350 }
351 }
352#endif
353 return MFChanged;
354}
unsigned const MachineRegisterInfo * MRI
MachineInstrBuilder & UseMI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
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.
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.
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:167
#define LLVM_DEBUG(...)
Definition: Debug.h:119
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:39
Combiner(MachineFunction &MF, CombinerInfo &CInfo, const TargetPassConfig *TPC, GISelValueTracking *VT, 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
GISelCSEInfo * CSEInfo
Definition: Combiner.h:78
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
GISelValueTracking * VT
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, GISelValueTracking *vt, CodeGenCoverage *covinfo=nullptr, ProfileSummaryInfo *psi=nullptr, BlockFrequencyInfo *bfi=nullptr)
Setup per-MF executor state.
The CSE Analysis object.
Definition: CSEInfo.h:71
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
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:72
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI 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
LLVM_ABI 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:74
bool remove(const value_type &X)
Remove an item from the set vector.
Definition: SetVector.h:198
void clear()
Completely clear the SetVector.
Definition: SetVector.h:284
bool empty() const
Determine if the SetVector is empty or not.
Definition: SetVector.h:99
bool insert(const value_type &X)
Insert a new element into the SetVector.
Definition: SetVector.h:168
value_type pop_back_val()
Definition: SetVector.h:296
A SetVector that performs no allocations if smaller than a certain size.
Definition: SetVector.h:356
Target-Independent Code Generator Pass Configuration Options.
A Use represents the edge between a Value definition and its users.
Definition: Use.h:35
#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
LLVM_ABI 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:1723
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:663
iterator_range< po_iterator< T > > post_order(const T &G)
auto reverse(ContainerTy &&C)
Definition: STLExtras.h:428
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:207
LLVM_ABI 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.")
LLVM_ABI 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:856
#define MORE()
Definition: regcomp.c:246
#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.