xref: /freebsd-src/contrib/llvm-project/llvm/lib/CodeGen/GlobalISel/Combiner.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===-- lib/CodeGen/GlobalISel/Combiner.cpp -------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file constains common code to combine machine functions at generic
100b57cec5SDimitry Andric // level.
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/Combiner.h"
140b57cec5SDimitry Andric #include "llvm/ADT/PostOrderIterator.h"
15bdd1243dSDimitry Andric #include "llvm/ADT/SetVector.h"
16*0fca6ea1SDimitry Andric #include "llvm/ADT/Statistic.h"
170b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/CSEInfo.h"
180b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/CSEMIRBuilder.h"
1981ad6265SDimitry Andric #include "llvm/CodeGen/GlobalISel/CombinerInfo.h"
200b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h"
210b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/GISelWorkList.h"
220b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
230b57cec5SDimitry Andric #include "llvm/CodeGen/GlobalISel/Utils.h"
240b57cec5SDimitry Andric #include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
250b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric #define DEBUG_TYPE "gi-combiner"
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric using namespace llvm;
300b57cec5SDimitry Andric 
31*0fca6ea1SDimitry Andric STATISTIC(NumOneIteration, "Number of functions with one iteration");
32*0fca6ea1SDimitry Andric STATISTIC(NumTwoIterations, "Number of functions with two iterations");
33*0fca6ea1SDimitry Andric STATISTIC(NumThreeOrMoreIterations,
34*0fca6ea1SDimitry Andric           "Number of functions with three or more iterations");
35*0fca6ea1SDimitry Andric 
368bcb0991SDimitry Andric namespace llvm {
378bcb0991SDimitry Andric cl::OptionCategory GICombinerOptionCategory(
388bcb0991SDimitry Andric     "GlobalISel Combiner",
398bcb0991SDimitry Andric     "Control the rules which are enabled. These options all take a comma "
408bcb0991SDimitry Andric     "separated list of rules to disable and may be specified by number "
418bcb0991SDimitry Andric     "or number range (e.g. 1-10)."
428bcb0991SDimitry Andric #ifndef NDEBUG
438bcb0991SDimitry Andric     " They may also be specified by name."
448bcb0991SDimitry Andric #endif
458bcb0991SDimitry Andric );
468bcb0991SDimitry Andric } // end namespace llvm
478bcb0991SDimitry Andric 
480b57cec5SDimitry Andric /// This class acts as the glue the joins the CombinerHelper to the overall
490b57cec5SDimitry Andric /// Combine algorithm. The CombinerHelper is intended to report the
500b57cec5SDimitry Andric /// modifications it makes to the MIR to the GISelChangeObserver and the
510b57cec5SDimitry Andric /// observer subclass will act on these events. In this case, instruction
520b57cec5SDimitry Andric /// erasure will cancel any future visits to the erased instruction and
530b57cec5SDimitry Andric /// instruction creation will schedule that instruction for a future visit.
540b57cec5SDimitry Andric /// Other Combiner implementations may require more complex behaviour from
550b57cec5SDimitry Andric /// their GISelChangeObserver subclass.
565f757f3fSDimitry Andric class Combiner::WorkListMaintainer : public GISelChangeObserver {
570b57cec5SDimitry Andric   using WorkListTy = GISelWorkList<512>;
580b57cec5SDimitry Andric   WorkListTy &WorkList;
590b57cec5SDimitry Andric   /// The instructions that have been created but we want to report once they
600b57cec5SDimitry Andric   /// have their operands. This is only maintained if debug output is requested.
61bdd1243dSDimitry Andric #ifndef NDEBUG
62bdd1243dSDimitry Andric   SetVector<const MachineInstr *> CreatedInstrs;
63bdd1243dSDimitry Andric #endif
640b57cec5SDimitry Andric 
650b57cec5SDimitry Andric public:
6604eeddc0SDimitry Andric   WorkListMaintainer(WorkListTy &WorkList) : WorkList(WorkList) {}
6781ad6265SDimitry Andric   virtual ~WorkListMaintainer() = default;
680b57cec5SDimitry Andric 
690b57cec5SDimitry Andric   void erasingInstr(MachineInstr &MI) override {
700b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Erasing: " << MI << "\n");
710b57cec5SDimitry Andric     WorkList.remove(&MI);
720b57cec5SDimitry Andric   }
730b57cec5SDimitry Andric   void createdInstr(MachineInstr &MI) override {
740b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Creating: " << MI << "\n");
750b57cec5SDimitry Andric     WorkList.insert(&MI);
760b57cec5SDimitry Andric     LLVM_DEBUG(CreatedInstrs.insert(&MI));
770b57cec5SDimitry Andric   }
780b57cec5SDimitry Andric   void changingInstr(MachineInstr &MI) override {
790b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Changing: " << MI << "\n");
800b57cec5SDimitry Andric     WorkList.insert(&MI);
810b57cec5SDimitry Andric   }
820b57cec5SDimitry Andric   void changedInstr(MachineInstr &MI) override {
830b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Changed: " << MI << "\n");
840b57cec5SDimitry Andric     WorkList.insert(&MI);
850b57cec5SDimitry Andric   }
860b57cec5SDimitry Andric 
870b57cec5SDimitry Andric   void reportFullyCreatedInstrs() {
880b57cec5SDimitry Andric     LLVM_DEBUG(for (const auto *MI
890b57cec5SDimitry Andric                     : CreatedInstrs) {
900b57cec5SDimitry Andric       dbgs() << "Created: ";
910b57cec5SDimitry Andric       MI->print(dbgs());
920b57cec5SDimitry Andric     });
930b57cec5SDimitry Andric     LLVM_DEBUG(CreatedInstrs.clear());
940b57cec5SDimitry Andric   }
950b57cec5SDimitry Andric };
960b57cec5SDimitry Andric 
975f757f3fSDimitry Andric Combiner::Combiner(MachineFunction &MF, CombinerInfo &CInfo,
985f757f3fSDimitry Andric                    const TargetPassConfig *TPC, GISelKnownBits *KB,
995f757f3fSDimitry Andric                    GISelCSEInfo *CSEInfo)
1005f757f3fSDimitry Andric     : Builder(CSEInfo ? std::make_unique<CSEMIRBuilder>()
1015f757f3fSDimitry Andric                       : std::make_unique<MachineIRBuilder>()),
1025f757f3fSDimitry Andric       WLObserver(std::make_unique<WorkListMaintainer>(WorkList)),
1035f757f3fSDimitry Andric       ObserverWrapper(std::make_unique<GISelObserverWrapper>()), CInfo(CInfo),
1045f757f3fSDimitry Andric       Observer(*ObserverWrapper), B(*Builder), MF(MF), MRI(MF.getRegInfo()),
1055f757f3fSDimitry Andric       KB(KB), TPC(TPC), CSEInfo(CSEInfo) {
1060b57cec5SDimitry Andric   (void)this->TPC; // FIXME: Remove when used.
1075f757f3fSDimitry Andric 
1085f757f3fSDimitry Andric   // Setup builder.
1095f757f3fSDimitry Andric   B.setMF(MF);
1105f757f3fSDimitry Andric   if (CSEInfo)
1115f757f3fSDimitry Andric     B.setCSEInfo(CSEInfo);
1125f757f3fSDimitry Andric 
1135f757f3fSDimitry Andric   // Setup observer.
1145f757f3fSDimitry Andric   ObserverWrapper->addObserver(WLObserver.get());
1155f757f3fSDimitry Andric   if (CSEInfo)
1165f757f3fSDimitry Andric     ObserverWrapper->addObserver(CSEInfo);
1175f757f3fSDimitry Andric 
1185f757f3fSDimitry Andric   B.setChangeObserver(*ObserverWrapper);
1190b57cec5SDimitry Andric }
1200b57cec5SDimitry Andric 
1215f757f3fSDimitry Andric Combiner::~Combiner() = default;
1225f757f3fSDimitry Andric 
1235f757f3fSDimitry Andric bool Combiner::combineMachineInstrs() {
1240b57cec5SDimitry Andric   // If the ISel pipeline failed, do not bother running this pass.
1250b57cec5SDimitry Andric   // FIXME: Should this be here or in individual combiner passes.
1260b57cec5SDimitry Andric   if (MF.getProperties().hasProperty(
1270b57cec5SDimitry Andric           MachineFunctionProperties::Property::FailedISel))
1280b57cec5SDimitry Andric     return false;
1290b57cec5SDimitry Andric 
1305f757f3fSDimitry Andric   // We can't call this in the constructor because the derived class is
1315f757f3fSDimitry Andric   // uninitialized at that time.
1325f757f3fSDimitry Andric   if (!HasSetupMF) {
1335f757f3fSDimitry Andric     HasSetupMF = true;
1345f757f3fSDimitry Andric     setupMF(MF, KB);
1355f757f3fSDimitry Andric   }
1360b57cec5SDimitry Andric 
1370b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Generic MI Combiner for: " << MF.getName() << '\n');
1380b57cec5SDimitry Andric 
1390b57cec5SDimitry Andric   MachineOptimizationRemarkEmitter MORE(MF, /*MBFI=*/nullptr);
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric   bool MFChanged = false;
1420b57cec5SDimitry Andric   bool Changed;
1430b57cec5SDimitry Andric 
144*0fca6ea1SDimitry Andric   unsigned Iteration = 0;
145*0fca6ea1SDimitry Andric   while (true) {
146*0fca6ea1SDimitry Andric     ++Iteration;
147*0fca6ea1SDimitry Andric     LLVM_DEBUG(dbgs() << "\n\nCombiner iteration #" << Iteration << '\n');
148*0fca6ea1SDimitry Andric 
1495f757f3fSDimitry Andric     WorkList.clear();
1505f757f3fSDimitry Andric 
1510b57cec5SDimitry Andric     // Collect all instructions. Do a post order traversal for basic blocks and
1520b57cec5SDimitry Andric     // insert with list bottom up, so while we pop_back_val, we'll traverse top
1530b57cec5SDimitry Andric     // down RPOT.
1540b57cec5SDimitry Andric     Changed = false;
1555f757f3fSDimitry Andric 
1565f757f3fSDimitry Andric     RAIIDelegateInstaller DelInstall(MF, ObserverWrapper.get());
1570b57cec5SDimitry Andric     for (MachineBasicBlock *MBB : post_order(&MF)) {
158349cc55cSDimitry Andric       for (MachineInstr &CurMI :
159349cc55cSDimitry Andric            llvm::make_early_inc_range(llvm::reverse(*MBB))) {
1600b57cec5SDimitry Andric         // Erase dead insts before even adding to the list.
1615f757f3fSDimitry Andric         if (isTriviallyDead(CurMI, MRI)) {
162349cc55cSDimitry Andric           LLVM_DEBUG(dbgs() << CurMI << "Is dead; erasing.\n");
1635f757f3fSDimitry Andric           llvm::salvageDebugInfo(MRI, CurMI);
1640eae32dcSDimitry Andric           CurMI.eraseFromParent();
1650b57cec5SDimitry Andric           continue;
1660b57cec5SDimitry Andric         }
167349cc55cSDimitry Andric         WorkList.deferred_insert(&CurMI);
1680b57cec5SDimitry Andric       }
1690b57cec5SDimitry Andric     }
1700b57cec5SDimitry Andric     WorkList.finalize();
1710b57cec5SDimitry Andric     // Main Loop. Process the instructions here.
1720b57cec5SDimitry Andric     while (!WorkList.empty()) {
1730b57cec5SDimitry Andric       MachineInstr *CurrInst = WorkList.pop_back_val();
1740b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "\nTry combining " << *CurrInst;);
1755f757f3fSDimitry Andric       Changed |= tryCombineAll(*CurrInst);
1765f757f3fSDimitry Andric       WLObserver->reportFullyCreatedInstrs();
1770b57cec5SDimitry Andric     }
1780b57cec5SDimitry Andric     MFChanged |= Changed;
179*0fca6ea1SDimitry Andric 
180*0fca6ea1SDimitry Andric     if (!Changed) {
181*0fca6ea1SDimitry Andric       LLVM_DEBUG(dbgs() << "\nCombiner reached fixed-point after iteration #"
182*0fca6ea1SDimitry Andric                         << Iteration << '\n');
183*0fca6ea1SDimitry Andric       break;
184*0fca6ea1SDimitry Andric     }
185*0fca6ea1SDimitry Andric     // Iterate until a fixed-point is reached if MaxIterations == 0,
186*0fca6ea1SDimitry Andric     // otherwise limit the number of iterations.
187*0fca6ea1SDimitry Andric     if (CInfo.MaxIterations && Iteration >= CInfo.MaxIterations) {
188*0fca6ea1SDimitry Andric       LLVM_DEBUG(
189*0fca6ea1SDimitry Andric           dbgs() << "\nCombiner reached iteration limit after iteration #"
190*0fca6ea1SDimitry Andric                  << Iteration << '\n');
191*0fca6ea1SDimitry Andric       break;
192*0fca6ea1SDimitry Andric     }
193*0fca6ea1SDimitry Andric   }
194*0fca6ea1SDimitry Andric 
195*0fca6ea1SDimitry Andric   if (Iteration == 1)
196*0fca6ea1SDimitry Andric     ++NumOneIteration;
197*0fca6ea1SDimitry Andric   else if (Iteration == 2)
198*0fca6ea1SDimitry Andric     ++NumTwoIterations;
199*0fca6ea1SDimitry Andric   else
200*0fca6ea1SDimitry Andric     ++NumThreeOrMoreIterations;
2010b57cec5SDimitry Andric 
202fe6060f1SDimitry Andric #ifndef NDEBUG
203fe6060f1SDimitry Andric   if (CSEInfo) {
204fe6060f1SDimitry Andric     if (auto E = CSEInfo->verify()) {
205fe6060f1SDimitry Andric       errs() << E << '\n';
206fe6060f1SDimitry Andric       assert(false && "CSEInfo is not consistent. Likely missing calls to "
207fe6060f1SDimitry Andric                       "observer on mutations.");
208fe6060f1SDimitry Andric     }
209fe6060f1SDimitry Andric   }
210fe6060f1SDimitry Andric #endif
2110b57cec5SDimitry Andric   return MFChanged;
2120b57cec5SDimitry Andric }
213