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