Combiner.cpp revision 355940
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/CodeGen/GlobalISel/CSEInfo.h" 16#include "llvm/CodeGen/GlobalISel/CombinerInfo.h" 17#include "llvm/CodeGen/GlobalISel/CSEMIRBuilder.h" 18#include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h" 19#include "llvm/CodeGen/GlobalISel/GISelWorkList.h" 20#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" 21#include "llvm/CodeGen/GlobalISel/Utils.h" 22#include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h" 23#include "llvm/CodeGen/MachineRegisterInfo.h" 24#include "llvm/Support/Debug.h" 25 26#define DEBUG_TYPE "gi-combiner" 27 28using namespace llvm; 29 30namespace { 31/// This class acts as the glue the joins the CombinerHelper to the overall 32/// Combine algorithm. The CombinerHelper is intended to report the 33/// modifications it makes to the MIR to the GISelChangeObserver and the 34/// observer subclass will act on these events. In this case, instruction 35/// erasure will cancel any future visits to the erased instruction and 36/// instruction creation will schedule that instruction for a future visit. 37/// Other Combiner implementations may require more complex behaviour from 38/// their GISelChangeObserver subclass. 39class WorkListMaintainer : public GISelChangeObserver { 40 using WorkListTy = GISelWorkList<512>; 41 WorkListTy &WorkList; 42 /// The instructions that have been created but we want to report once they 43 /// have their operands. This is only maintained if debug output is requested. 44 SmallPtrSet<const MachineInstr *, 4> CreatedInstrs; 45 46public: 47 WorkListMaintainer(WorkListTy &WorkList) 48 : GISelChangeObserver(), WorkList(WorkList) {} 49 virtual ~WorkListMaintainer() { 50 } 51 52 void erasingInstr(MachineInstr &MI) override { 53 LLVM_DEBUG(dbgs() << "Erasing: " << MI << "\n"); 54 WorkList.remove(&MI); 55 } 56 void createdInstr(MachineInstr &MI) override { 57 LLVM_DEBUG(dbgs() << "Creating: " << MI << "\n"); 58 WorkList.insert(&MI); 59 LLVM_DEBUG(CreatedInstrs.insert(&MI)); 60 } 61 void changingInstr(MachineInstr &MI) override { 62 LLVM_DEBUG(dbgs() << "Changing: " << MI << "\n"); 63 WorkList.insert(&MI); 64 } 65 void changedInstr(MachineInstr &MI) override { 66 LLVM_DEBUG(dbgs() << "Changed: " << MI << "\n"); 67 WorkList.insert(&MI); 68 } 69 70 void reportFullyCreatedInstrs() { 71 LLVM_DEBUG(for (const auto *MI 72 : CreatedInstrs) { 73 dbgs() << "Created: "; 74 MI->print(dbgs()); 75 }); 76 LLVM_DEBUG(CreatedInstrs.clear()); 77 } 78}; 79} 80 81Combiner::Combiner(CombinerInfo &Info, const TargetPassConfig *TPC) 82 : CInfo(Info), TPC(TPC) { 83 (void)this->TPC; // FIXME: Remove when used. 84} 85 86bool Combiner::combineMachineInstrs(MachineFunction &MF, 87 GISelCSEInfo *CSEInfo) { 88 // If the ISel pipeline failed, do not bother running this pass. 89 // FIXME: Should this be here or in individual combiner passes. 90 if (MF.getProperties().hasProperty( 91 MachineFunctionProperties::Property::FailedISel)) 92 return false; 93 94 Builder = 95 CSEInfo ? make_unique<CSEMIRBuilder>() : make_unique<MachineIRBuilder>(); 96 MRI = &MF.getRegInfo(); 97 Builder->setMF(MF); 98 if (CSEInfo) 99 Builder->setCSEInfo(CSEInfo); 100 101 LLVM_DEBUG(dbgs() << "Generic MI Combiner for: " << MF.getName() << '\n'); 102 103 MachineOptimizationRemarkEmitter MORE(MF, /*MBFI=*/nullptr); 104 105 bool MFChanged = false; 106 bool Changed; 107 MachineIRBuilder &B = *Builder.get(); 108 109 do { 110 // Collect all instructions. Do a post order traversal for basic blocks and 111 // insert with list bottom up, so while we pop_back_val, we'll traverse top 112 // down RPOT. 113 Changed = false; 114 GISelWorkList<512> WorkList; 115 WorkListMaintainer Observer(WorkList); 116 GISelObserverWrapper WrapperObserver(&Observer); 117 if (CSEInfo) 118 WrapperObserver.addObserver(CSEInfo); 119 RAIIDelegateInstaller DelInstall(MF, &WrapperObserver); 120 for (MachineBasicBlock *MBB : post_order(&MF)) { 121 if (MBB->empty()) 122 continue; 123 for (auto MII = MBB->rbegin(), MIE = MBB->rend(); MII != MIE;) { 124 MachineInstr *CurMI = &*MII; 125 ++MII; 126 // Erase dead insts before even adding to the list. 127 if (isTriviallyDead(*CurMI, *MRI)) { 128 LLVM_DEBUG(dbgs() << *CurMI << "Is dead; erasing.\n"); 129 CurMI->eraseFromParentAndMarkDBGValuesForRemoval(); 130 continue; 131 } 132 WorkList.deferred_insert(CurMI); 133 } 134 } 135 WorkList.finalize(); 136 // Main Loop. Process the instructions here. 137 while (!WorkList.empty()) { 138 MachineInstr *CurrInst = WorkList.pop_back_val(); 139 LLVM_DEBUG(dbgs() << "\nTry combining " << *CurrInst;); 140 Changed |= CInfo.combine(WrapperObserver, *CurrInst, B); 141 Observer.reportFullyCreatedInstrs(); 142 } 143 MFChanged |= Changed; 144 } while (Changed); 145 146 return MFChanged; 147} 148