xref: /llvm-project/llvm/lib/CodeGen/GlobalISel/Combiner.cpp (revision 9659bfda5a6493241c6e62bcc54c74f33d045c88)
1 //===-- lib/CodeGen/GlobalISel/GICombiner.cpp -----------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file constains common code to combine machine functions at generic
11 // level.
12 //===----------------------------------------------------------------------===//
13 
14 #include "llvm/CodeGen/GlobalISel/Combiner.h"
15 #include "llvm/CodeGen/GlobalISel/CombinerInfo.h"
16 #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
17 #include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
18 #include "llvm/CodeGen/GlobalISel/GISelWorkList.h"
19 #include "llvm/ADT/PostOrderIterator.h"
20 #include "llvm/CodeGen/GlobalISel/Utils.h"
21 #include "llvm/CodeGen/MachineRegisterInfo.h"
22 #include "llvm/Support/Debug.h"
23 
24 #define DEBUG_TYPE "gi-combiner"
25 
26 using namespace llvm;
27 
28 namespace {
29 /// This class acts as the glue the joins the CombinerHelper to the overall
30 /// Combine algorithm. The CombinerHelper is intended to report the
31 /// modifications it makes to the MIR to the CombinerChangeObserver and the
32 /// observer subclass will act on these events. In this case, instruction
33 /// erasure will cancel any future visits to the erased instruction and
34 /// instruction creation will schedule that instruction for a future visit.
35 /// Other Combiner implementations may require more complex behaviour from
36 /// their CombinerChangeObserver subclass.
37 class WorkListMaintainer : public CombinerChangeObserver {
38   using WorkListTy = GISelWorkList<512>;
39   WorkListTy &WorkList;
40 
41 public:
42   WorkListMaintainer(WorkListTy &WorkList) : WorkList(WorkList) {}
43   virtual ~WorkListMaintainer() {}
44 
45   void erasedInstr(MachineInstr &MI) override {
46     LLVM_DEBUG(dbgs() << "Erased: "; MI.print(dbgs()); dbgs() << "\n");
47     WorkList.remove(&MI);
48   }
49   void createdInstr(MachineInstr &MI) override {
50     LLVM_DEBUG(dbgs() << "Created: "; MI.print(dbgs()); dbgs() << "\n");
51     WorkList.insert(&MI);
52   }
53 };
54 }
55 
56 Combiner::Combiner(CombinerInfo &Info, const TargetPassConfig *TPC)
57     : CInfo(Info), TPC(TPC) {
58   (void)this->TPC; // FIXME: Remove when used.
59 }
60 
61 bool Combiner::combineMachineInstrs(MachineFunction &MF) {
62   // If the ISel pipeline failed, do not bother running this pass.
63   // FIXME: Should this be here or in individual combiner passes.
64   if (MF.getProperties().hasProperty(
65           MachineFunctionProperties::Property::FailedISel))
66     return false;
67 
68   MRI = &MF.getRegInfo();
69   Builder.setMF(MF);
70 
71   LLVM_DEBUG(dbgs() << "Generic MI Combiner for: " << MF.getName() << '\n');
72 
73   MachineOptimizationRemarkEmitter MORE(MF, /*MBFI=*/nullptr);
74 
75   bool MFChanged = false;
76   bool Changed;
77 
78   do {
79     // Collect all instructions. Do a post order traversal for basic blocks and
80     // insert with list bottom up, so while we pop_back_val, we'll traverse top
81     // down RPOT.
82     Changed = false;
83     GISelWorkList<512> WorkList;
84     WorkListMaintainer Observer(WorkList);
85     for (MachineBasicBlock *MBB : post_order(&MF)) {
86       if (MBB->empty())
87         continue;
88       for (auto MII = MBB->rbegin(), MIE = MBB->rend(); MII != MIE;) {
89         MachineInstr *CurMI = &*MII;
90         ++MII;
91         // Erase dead insts before even adding to the list.
92         if (isTriviallyDead(*CurMI, *MRI)) {
93           LLVM_DEBUG(dbgs() << *CurMI << "Is dead; erasing.\n");
94           CurMI->eraseFromParentAndMarkDBGValuesForRemoval();
95           continue;
96         }
97         WorkList.insert(CurMI);
98       }
99     }
100     // Main Loop. Process the instructions here.
101     while (!WorkList.empty()) {
102       MachineInstr *CurrInst = WorkList.pop_back_val();
103       LLVM_DEBUG(dbgs() << "Try combining " << *CurrInst << "\n";);
104       Changed |= CInfo.combine(Observer, *CurrInst, Builder);
105     }
106     MFChanged |= Changed;
107   } while (Changed);
108 
109   return MFChanged;
110 }
111