xref: /llvm-project/llvm/lib/CodeGen/GlobalISel/Combiner.cpp (revision a4525fcc8f127139a493164c360725ae4c6c87b3)
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 
13 #include "llvm/CodeGen/GlobalISel/Combiner.h"
14 #include "llvm/ADT/PostOrderIterator.h"
15 #include "llvm/ADT/SetVector.h"
16 #include "llvm/ADT/Statistic.h"
17 #include "llvm/CodeGen/GlobalISel/CSEInfo.h"
18 #include "llvm/CodeGen/GlobalISel/CSEMIRBuilder.h"
19 #include "llvm/CodeGen/GlobalISel/CombinerInfo.h"
20 #include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h"
21 #include "llvm/CodeGen/GlobalISel/GISelWorkList.h"
22 #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
23 #include "llvm/CodeGen/GlobalISel/Utils.h"
24 #include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
25 #include "llvm/Support/Debug.h"
26 
27 #define DEBUG_TYPE "gi-combiner"
28 
29 using namespace llvm;
30 
31 STATISTIC(NumOneIteration, "Number of functions with one iteration");
32 STATISTIC(NumTwoIterations, "Number of functions with two iterations");
33 STATISTIC(NumThreeOrMoreIterations,
34           "Number of functions with three or more iterations");
35 
36 namespace llvm {
37 cl::OptionCategory GICombinerOptionCategory(
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.
52 class Combiner::WorkListMaintainer : public GISelChangeObserver {
53 protected:
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.
57   SmallSetVector<const MachineInstr *, 32> CreatedInstrs;
58 #endif
59   using Level = CombinerInfo::ObserverLevel;
60 
61 public:
62   static std::unique_ptr<WorkListMaintainer>
63   create(Level Lvl, WorkListTy &WorkList, MachineRegisterInfo &MRI);
64 
65   virtual ~WorkListMaintainer() = default;
66 
67   void reportFullyCreatedInstrs() {
68     LLVM_DEBUG({
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.
83 template <CombinerInfo::ObserverLevel Lvl>
84 class Combiner::WorkListMaintainerImpl : public Combiner::WorkListMaintainer {
85   WorkListTy &WorkList;
86   MachineRegisterInfo &MRI;
87 
88   // Defer handling these instructions until the combine finishes.
89   SmallSetVector<MachineInstr *, 32> DeferList;
90 
91   // Track VRegs that (might) have lost a use.
92   SmallSetVector<Register, 32> LostUses;
93 
94 public:
95   WorkListMaintainerImpl(WorkListTy &WorkList, MachineRegisterInfo &MRI)
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);
111       noteLostUses(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)
133       noteLostUses(MI);
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)
160         addUsersToWorkList(MI);
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();
168       MachineInstr *UseMI = MRI.getVRegDef(Use);
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.
180         if (MRI.hasOneNonDBGUser(Use))
181           WorkList.insert(&*MRI.use_instr_nodbg_begin(Use));
182 
183         WorkList.insert(UseMI);
184       }
185     }
186   }
187 
188   void noteLostUses(MachineInstr &MI) {
189     for (auto &Use : MI.explicit_uses()) {
190       if (!Use.isReg() || !Use.getReg().isVirtual())
191         continue;
192       LostUses.insert(Use.getReg());
193     }
194   }
195 
196   void addUsersToWorkList(MachineInstr &MI) {
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 
208 std::unique_ptr<Combiner::WorkListMaintainer>
209 Combiner::WorkListMaintainer::create(Level Lvl, WorkListTy &WorkList,
210                                      MachineRegisterInfo &MRI) {
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 
224 Combiner::Combiner(MachineFunction &MF, CombinerInfo &CInfo,
225                    const TargetPassConfig *TPC, GISelKnownBits *KB,
226                    GISelCSEInfo *CSEInfo)
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)
239     B.setCSEInfo(CSEInfo);
240 
241   B.setChangeObserver(*ObserverWrapper);
242 }
243 
244 Combiner::~Combiner() = default;
245 
246 bool Combiner::tryDCE(MachineInstr &MI, MachineRegisterInfo &MRI) {
247   if (!isTriviallyDead(MI, MRI))
248     return false;
249   LLVM_DEBUG(dbgs() << "Dead: " << MI);
250   llvm::salvageDebugInfo(MRI, MI);
251   MI.eraseFromParent();
252   return true;
253 }
254 
255 bool Combiner::combineMachineInstrs() {
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().hasProperty(
259           MachineFunctionProperties::Property::FailedISel))
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.
290     bool EnableDCE = CInfo.ObserverLvl >= CombinerInfo::ObserverLevel::DCE
291                          ? CInfo.EnableFullDCE && Iteration == 1
292                          : CInfo.EnableFullDCE;
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);
298     for (MachineBasicBlock *MBB : post_order(&MF)) {
299       for (MachineInstr &CurMI :
300            llvm::make_early_inc_range(llvm::reverse(*MBB))) {
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) {
331       LLVM_DEBUG(
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 }
356