148 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			148 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===-- 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;
 | |
| }
 |