|  | //===-- lib/CodeGen/GlobalISel/Combiner.cpp -------------------------------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // This file constains common code to combine machine functions at generic | 
|  | // level. | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "llvm/CodeGen/GlobalISel/Combiner.h" | 
|  | #include "llvm/ADT/PostOrderIterator.h" | 
|  | #include "llvm/CodeGen/GlobalISel/CSEInfo.h" | 
|  | #include "llvm/CodeGen/GlobalISel/CombinerInfo.h" | 
|  | #include "llvm/CodeGen/GlobalISel/CSEMIRBuilder.h" | 
|  | #include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h" | 
|  | #include "llvm/CodeGen/GlobalISel/GISelWorkList.h" | 
|  | #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" | 
|  | #include "llvm/CodeGen/GlobalISel/Utils.h" | 
|  | #include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h" | 
|  | #include "llvm/CodeGen/MachineRegisterInfo.h" | 
|  | #include "llvm/Support/Debug.h" | 
|  |  | 
|  | #define DEBUG_TYPE "gi-combiner" | 
|  |  | 
|  | using namespace llvm; | 
|  |  | 
|  | namespace { | 
|  | /// This class acts as the glue the joins the CombinerHelper to the overall | 
|  | /// Combine algorithm. The CombinerHelper is intended to report the | 
|  | /// modifications it makes to the MIR to the GISelChangeObserver and the | 
|  | /// observer subclass will act on these events. In this case, instruction | 
|  | /// erasure will cancel any future visits to the erased instruction and | 
|  | /// instruction creation will schedule that instruction for a future visit. | 
|  | /// Other Combiner implementations may require more complex behaviour from | 
|  | /// their GISelChangeObserver subclass. | 
|  | class WorkListMaintainer : public GISelChangeObserver { | 
|  | using WorkListTy = GISelWorkList<512>; | 
|  | WorkListTy &WorkList; | 
|  | /// The instructions that have been created but we want to report once they | 
|  | /// have their operands. This is only maintained if debug output is requested. | 
|  | SmallPtrSet<const MachineInstr *, 4> CreatedInstrs; | 
|  |  | 
|  | public: | 
|  | WorkListMaintainer(WorkListTy &WorkList) | 
|  | : GISelChangeObserver(), WorkList(WorkList) {} | 
|  | virtual ~WorkListMaintainer() { | 
|  | } | 
|  |  | 
|  | void erasingInstr(MachineInstr &MI) override { | 
|  | LLVM_DEBUG(dbgs() << "Erasing: " << MI << "\n"); | 
|  | WorkList.remove(&MI); | 
|  | } | 
|  | void createdInstr(MachineInstr &MI) override { | 
|  | LLVM_DEBUG(dbgs() << "Creating: " << MI << "\n"); | 
|  | WorkList.insert(&MI); | 
|  | LLVM_DEBUG(CreatedInstrs.insert(&MI)); | 
|  | } | 
|  | void changingInstr(MachineInstr &MI) override { | 
|  | LLVM_DEBUG(dbgs() << "Changing: " << MI << "\n"); | 
|  | WorkList.insert(&MI); | 
|  | } | 
|  | void changedInstr(MachineInstr &MI) override { | 
|  | LLVM_DEBUG(dbgs() << "Changed: " << MI << "\n"); | 
|  | WorkList.insert(&MI); | 
|  | } | 
|  |  | 
|  | void reportFullyCreatedInstrs() { | 
|  | LLVM_DEBUG(for (const auto *MI | 
|  | : CreatedInstrs) { | 
|  | dbgs() << "Created: "; | 
|  | MI->print(dbgs()); | 
|  | }); | 
|  | LLVM_DEBUG(CreatedInstrs.clear()); | 
|  | } | 
|  | }; | 
|  | } | 
|  |  | 
|  | Combiner::Combiner(CombinerInfo &Info, const TargetPassConfig *TPC) | 
|  | : CInfo(Info), TPC(TPC) { | 
|  | (void)this->TPC; // FIXME: Remove when used. | 
|  | } | 
|  |  | 
|  | bool Combiner::combineMachineInstrs(MachineFunction &MF, | 
|  | GISelCSEInfo *CSEInfo) { | 
|  | // If the ISel pipeline failed, do not bother running this pass. | 
|  | // FIXME: Should this be here or in individual combiner passes. | 
|  | if (MF.getProperties().hasProperty( | 
|  | MachineFunctionProperties::Property::FailedISel)) | 
|  | return false; | 
|  |  | 
|  | Builder = | 
|  | CSEInfo ? make_unique<CSEMIRBuilder>() : make_unique<MachineIRBuilder>(); | 
|  | MRI = &MF.getRegInfo(); | 
|  | Builder->setMF(MF); | 
|  | if (CSEInfo) | 
|  | Builder->setCSEInfo(CSEInfo); | 
|  |  | 
|  | LLVM_DEBUG(dbgs() << "Generic MI Combiner for: " << MF.getName() << '\n'); | 
|  |  | 
|  | MachineOptimizationRemarkEmitter MORE(MF, /*MBFI=*/nullptr); | 
|  |  | 
|  | bool MFChanged = false; | 
|  | bool Changed; | 
|  | MachineIRBuilder &B = *Builder.get(); | 
|  |  | 
|  | do { | 
|  | // Collect all instructions. Do a post order traversal for basic blocks and | 
|  | // insert with list bottom up, so while we pop_back_val, we'll traverse top | 
|  | // down RPOT. | 
|  | Changed = false; | 
|  | GISelWorkList<512> WorkList; | 
|  | WorkListMaintainer Observer(WorkList); | 
|  | GISelObserverWrapper WrapperObserver(&Observer); | 
|  | if (CSEInfo) | 
|  | WrapperObserver.addObserver(CSEInfo); | 
|  | RAIIDelegateInstaller DelInstall(MF, &WrapperObserver); | 
|  | for (MachineBasicBlock *MBB : post_order(&MF)) { | 
|  | if (MBB->empty()) | 
|  | continue; | 
|  | for (auto MII = MBB->rbegin(), MIE = MBB->rend(); MII != MIE;) { | 
|  | MachineInstr *CurMI = &*MII; | 
|  | ++MII; | 
|  | // Erase dead insts before even adding to the list. | 
|  | if (isTriviallyDead(*CurMI, *MRI)) { | 
|  | LLVM_DEBUG(dbgs() << *CurMI << "Is dead; erasing.\n"); | 
|  | CurMI->eraseFromParentAndMarkDBGValuesForRemoval(); | 
|  | continue; | 
|  | } | 
|  | WorkList.deferred_insert(CurMI); | 
|  | } | 
|  | } | 
|  | WorkList.finalize(); | 
|  | // Main Loop. Process the instructions here. | 
|  | while (!WorkList.empty()) { | 
|  | MachineInstr *CurrInst = WorkList.pop_back_val(); | 
|  | LLVM_DEBUG(dbgs() << "\nTry combining " << *CurrInst;); | 
|  | Changed |= CInfo.combine(WrapperObserver, *CurrInst, B); | 
|  | Observer.reportFullyCreatedInstrs(); | 
|  | } | 
|  | MFChanged |= Changed; | 
|  | } while (Changed); | 
|  |  | 
|  | return MFChanged; | 
|  | } |