xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/Hexagon/HexagonCopyHoisting.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1*0fca6ea1SDimitry Andric //===--------- HexagonCopyHoisting.cpp - Hexagon Copy Hoisting  ----------===//
2*0fca6ea1SDimitry Andric //
3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0fca6ea1SDimitry Andric //
7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
8*0fca6ea1SDimitry Andric // The purpose of this pass is to move the copy instructions that are
9*0fca6ea1SDimitry Andric // present in all the successor of a basic block (BB) to the end of BB.
10*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
11*0fca6ea1SDimitry Andric 
12*0fca6ea1SDimitry Andric #include "HexagonTargetMachine.h"
13*0fca6ea1SDimitry Andric #include "llvm/ADT/DenseMap.h"
14*0fca6ea1SDimitry Andric #include "llvm/ADT/PostOrderIterator.h"
15*0fca6ea1SDimitry Andric #include "llvm/ADT/StringRef.h"
16*0fca6ea1SDimitry Andric #include "llvm/ADT/Twine.h"
17*0fca6ea1SDimitry Andric #include "llvm/CodeGen/LiveInterval.h"
18*0fca6ea1SDimitry Andric #include "llvm/CodeGen/LiveIntervals.h"
19*0fca6ea1SDimitry Andric #include "llvm/CodeGen/MachineDominators.h"
20*0fca6ea1SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
21*0fca6ea1SDimitry Andric #include "llvm/Support/CommandLine.h"
22*0fca6ea1SDimitry Andric #include "llvm/Support/Debug.h"
23*0fca6ea1SDimitry Andric 
24*0fca6ea1SDimitry Andric #define DEBUG_TYPE "CopyHoist"
25*0fca6ea1SDimitry Andric 
26*0fca6ea1SDimitry Andric using namespace llvm;
27*0fca6ea1SDimitry Andric 
28*0fca6ea1SDimitry Andric static cl::opt<std::string> CPHoistFn("cphoistfn", cl::Hidden, cl::desc(""),
29*0fca6ea1SDimitry Andric                                       cl::init(""));
30*0fca6ea1SDimitry Andric 
31*0fca6ea1SDimitry Andric namespace llvm {
32*0fca6ea1SDimitry Andric void initializeHexagonCopyHoistingPass(PassRegistry &Registry);
33*0fca6ea1SDimitry Andric FunctionPass *createHexagonCopyHoisting();
34*0fca6ea1SDimitry Andric } // namespace llvm
35*0fca6ea1SDimitry Andric 
36*0fca6ea1SDimitry Andric namespace {
37*0fca6ea1SDimitry Andric 
38*0fca6ea1SDimitry Andric class HexagonCopyHoisting : public MachineFunctionPass {
39*0fca6ea1SDimitry Andric 
40*0fca6ea1SDimitry Andric public:
41*0fca6ea1SDimitry Andric   static char ID;
42*0fca6ea1SDimitry Andric   HexagonCopyHoisting() : MachineFunctionPass(ID), MFN(nullptr), MRI(nullptr) {
43*0fca6ea1SDimitry Andric     initializeHexagonCopyHoistingPass(*PassRegistry::getPassRegistry());
44*0fca6ea1SDimitry Andric   }
45*0fca6ea1SDimitry Andric 
46*0fca6ea1SDimitry Andric   StringRef getPassName() const override { return "Hexagon Copy Hoisting"; }
47*0fca6ea1SDimitry Andric 
48*0fca6ea1SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
49*0fca6ea1SDimitry Andric     AU.addRequired<SlotIndexesWrapperPass>();
50*0fca6ea1SDimitry Andric     AU.addRequired<LiveIntervalsWrapperPass>();
51*0fca6ea1SDimitry Andric     AU.addPreserved<SlotIndexesWrapperPass>();
52*0fca6ea1SDimitry Andric     AU.addPreserved<LiveIntervalsWrapperPass>();
53*0fca6ea1SDimitry Andric     AU.addRequired<MachineDominatorTreeWrapperPass>();
54*0fca6ea1SDimitry Andric     AU.addPreserved<MachineDominatorTreeWrapperPass>();
55*0fca6ea1SDimitry Andric     MachineFunctionPass::getAnalysisUsage(AU);
56*0fca6ea1SDimitry Andric   }
57*0fca6ea1SDimitry Andric 
58*0fca6ea1SDimitry Andric   bool runOnMachineFunction(MachineFunction &Fn) override;
59*0fca6ea1SDimitry Andric   void collectCopyInst();
60*0fca6ea1SDimitry Andric   void addMItoCopyList(MachineInstr *MI);
61*0fca6ea1SDimitry Andric   bool analyzeCopy(MachineBasicBlock *BB);
62*0fca6ea1SDimitry Andric   bool isSafetoMove(MachineInstr *CandMI);
63*0fca6ea1SDimitry Andric   void moveCopyInstr(MachineBasicBlock *DestBB,
64*0fca6ea1SDimitry Andric                      std::pair<Register, Register> Key, MachineInstr *MI);
65*0fca6ea1SDimitry Andric 
66*0fca6ea1SDimitry Andric   MachineFunction *MFN;
67*0fca6ea1SDimitry Andric   MachineRegisterInfo *MRI;
68*0fca6ea1SDimitry Andric   std::vector<DenseMap<std::pair<Register, Register>, MachineInstr *>>
69*0fca6ea1SDimitry Andric       CopyMIList;
70*0fca6ea1SDimitry Andric };
71*0fca6ea1SDimitry Andric 
72*0fca6ea1SDimitry Andric } // namespace
73*0fca6ea1SDimitry Andric 
74*0fca6ea1SDimitry Andric char HexagonCopyHoisting::ID = 0;
75*0fca6ea1SDimitry Andric 
76*0fca6ea1SDimitry Andric namespace llvm {
77*0fca6ea1SDimitry Andric char &HexagonCopyHoistingID = HexagonCopyHoisting::ID;
78*0fca6ea1SDimitry Andric } // namespace llvm
79*0fca6ea1SDimitry Andric 
80*0fca6ea1SDimitry Andric bool HexagonCopyHoisting::runOnMachineFunction(MachineFunction &Fn) {
81*0fca6ea1SDimitry Andric 
82*0fca6ea1SDimitry Andric   if ((CPHoistFn != "") && (CPHoistFn != Fn.getFunction().getName()))
83*0fca6ea1SDimitry Andric     return false;
84*0fca6ea1SDimitry Andric 
85*0fca6ea1SDimitry Andric   MFN = &Fn;
86*0fca6ea1SDimitry Andric   MRI = &Fn.getRegInfo();
87*0fca6ea1SDimitry Andric 
88*0fca6ea1SDimitry Andric   LLVM_DEBUG(dbgs() << "\nCopy Hoisting:" << "\'" << Fn.getName() << "\'\n");
89*0fca6ea1SDimitry Andric 
90*0fca6ea1SDimitry Andric   CopyMIList.clear();
91*0fca6ea1SDimitry Andric   CopyMIList.resize(Fn.getNumBlockIDs());
92*0fca6ea1SDimitry Andric 
93*0fca6ea1SDimitry Andric   // Traverse through all basic blocks and collect copy instructions.
94*0fca6ea1SDimitry Andric   collectCopyInst();
95*0fca6ea1SDimitry Andric 
96*0fca6ea1SDimitry Andric   // Traverse through the basic blocks again and move the COPY instructions
97*0fca6ea1SDimitry Andric   // that are present in all the successors of BB to BB.
98*0fca6ea1SDimitry Andric   bool Changed = false;
99*0fca6ea1SDimitry Andric   for (MachineBasicBlock *BB : post_order(&Fn)) {
100*0fca6ea1SDimitry Andric     if (!BB->empty()) {
101*0fca6ea1SDimitry Andric       if (BB->pred_size() != 1)
102*0fca6ea1SDimitry Andric         continue;
103*0fca6ea1SDimitry Andric       auto &BBCopyInst = CopyMIList[BB->getNumber()];
104*0fca6ea1SDimitry Andric       if (BBCopyInst.size() > 0)
105*0fca6ea1SDimitry Andric         Changed |= analyzeCopy(*BB->pred_begin());
106*0fca6ea1SDimitry Andric     }
107*0fca6ea1SDimitry Andric   }
108*0fca6ea1SDimitry Andric   // Re-compute liveness
109*0fca6ea1SDimitry Andric   if (Changed) {
110*0fca6ea1SDimitry Andric     LiveIntervals &LIS = getAnalysis<LiveIntervalsWrapperPass>().getLIS();
111*0fca6ea1SDimitry Andric     SlotIndexes *SI = LIS.getSlotIndexes();
112*0fca6ea1SDimitry Andric     SI->reanalyze(Fn);
113*0fca6ea1SDimitry Andric     LIS.reanalyze(Fn);
114*0fca6ea1SDimitry Andric   }
115*0fca6ea1SDimitry Andric   return Changed;
116*0fca6ea1SDimitry Andric }
117*0fca6ea1SDimitry Andric 
118*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
119*0fca6ea1SDimitry Andric // Save all COPY instructions for each basic block in CopyMIList vector.
120*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
121*0fca6ea1SDimitry Andric void HexagonCopyHoisting::collectCopyInst() {
122*0fca6ea1SDimitry Andric   for (MachineBasicBlock &BB : *MFN) {
123*0fca6ea1SDimitry Andric #ifndef NDEBUG
124*0fca6ea1SDimitry Andric     auto &BBCopyInst = CopyMIList[BB.getNumber()];
125*0fca6ea1SDimitry Andric     LLVM_DEBUG(dbgs() << "Visiting BB#" << BB.getNumber() << ":\n");
126*0fca6ea1SDimitry Andric #endif
127*0fca6ea1SDimitry Andric 
128*0fca6ea1SDimitry Andric     for (MachineInstr &MI : BB) {
129*0fca6ea1SDimitry Andric       if (MI.getOpcode() == TargetOpcode::COPY)
130*0fca6ea1SDimitry Andric         addMItoCopyList(&MI);
131*0fca6ea1SDimitry Andric     }
132*0fca6ea1SDimitry Andric     LLVM_DEBUG(dbgs() << "\tNumber of copies: " << BBCopyInst.size() << "\n");
133*0fca6ea1SDimitry Andric   }
134*0fca6ea1SDimitry Andric }
135*0fca6ea1SDimitry Andric 
136*0fca6ea1SDimitry Andric void HexagonCopyHoisting::addMItoCopyList(MachineInstr *MI) {
137*0fca6ea1SDimitry Andric   unsigned BBNum = MI->getParent()->getNumber();
138*0fca6ea1SDimitry Andric   auto &BBCopyInst = CopyMIList[BBNum];
139*0fca6ea1SDimitry Andric   Register DstReg = MI->getOperand(0).getReg();
140*0fca6ea1SDimitry Andric   Register SrcReg = MI->getOperand(1).getReg();
141*0fca6ea1SDimitry Andric 
142*0fca6ea1SDimitry Andric   if (!Register::isVirtualRegister(DstReg) ||
143*0fca6ea1SDimitry Andric       !Register::isVirtualRegister(SrcReg) ||
144*0fca6ea1SDimitry Andric       MRI->getRegClass(DstReg) != &Hexagon::IntRegsRegClass ||
145*0fca6ea1SDimitry Andric       MRI->getRegClass(SrcReg) != &Hexagon::IntRegsRegClass)
146*0fca6ea1SDimitry Andric     return;
147*0fca6ea1SDimitry Andric 
148*0fca6ea1SDimitry Andric   BBCopyInst.insert(std::pair(std::pair(SrcReg, DstReg), MI));
149*0fca6ea1SDimitry Andric #ifndef NDEBUG
150*0fca6ea1SDimitry Andric   LLVM_DEBUG(dbgs() << "\tAdding Copy Instr to the list: " << MI << "\n");
151*0fca6ea1SDimitry Andric   for (auto II : BBCopyInst) {
152*0fca6ea1SDimitry Andric     MachineInstr *TempMI = II.getSecond();
153*0fca6ea1SDimitry Andric     LLVM_DEBUG(dbgs() << "\tIn the list: " << TempMI << "\n");
154*0fca6ea1SDimitry Andric   }
155*0fca6ea1SDimitry Andric #endif
156*0fca6ea1SDimitry Andric }
157*0fca6ea1SDimitry Andric 
158*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
159*0fca6ea1SDimitry Andric // Look at the COPY instructions of all the successors of BB. If the same
160*0fca6ea1SDimitry Andric // instruction is present in every successor and can be safely moved,
161*0fca6ea1SDimitry Andric // pull it into BB.
162*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
163*0fca6ea1SDimitry Andric bool HexagonCopyHoisting::analyzeCopy(MachineBasicBlock *BB) {
164*0fca6ea1SDimitry Andric 
165*0fca6ea1SDimitry Andric   bool Changed = false;
166*0fca6ea1SDimitry Andric   if (BB->succ_size() < 2)
167*0fca6ea1SDimitry Andric     return false;
168*0fca6ea1SDimitry Andric 
169*0fca6ea1SDimitry Andric   for (MachineBasicBlock *SB : BB->successors()) {
170*0fca6ea1SDimitry Andric     if (SB->pred_size() != 1 || SB->isEHPad() || SB->hasAddressTaken())
171*0fca6ea1SDimitry Andric       return false;
172*0fca6ea1SDimitry Andric   }
173*0fca6ea1SDimitry Andric 
174*0fca6ea1SDimitry Andric   MachineBasicBlock *SBB1 = *BB->succ_begin();
175*0fca6ea1SDimitry Andric   auto &BBCopyInst1 = CopyMIList[SBB1->getNumber()];
176*0fca6ea1SDimitry Andric 
177*0fca6ea1SDimitry Andric   for (auto II : BBCopyInst1) {
178*0fca6ea1SDimitry Andric     std::pair<Register, Register> Key = II.getFirst();
179*0fca6ea1SDimitry Andric     MachineInstr *MI = II.getSecond();
180*0fca6ea1SDimitry Andric     bool IsSafetoMove = true;
181*0fca6ea1SDimitry Andric     for (MachineBasicBlock *SuccBB : BB->successors()) {
182*0fca6ea1SDimitry Andric       auto &SuccBBCopyInst = CopyMIList[SuccBB->getNumber()];
183*0fca6ea1SDimitry Andric       if (!SuccBBCopyInst.count(Key)) {
184*0fca6ea1SDimitry Andric         // Same copy not present in this successor
185*0fca6ea1SDimitry Andric         IsSafetoMove = false;
186*0fca6ea1SDimitry Andric         break;
187*0fca6ea1SDimitry Andric       }
188*0fca6ea1SDimitry Andric       // If present, make sure that it's safe to pull this copy instruction
189*0fca6ea1SDimitry Andric       // into the predecessor.
190*0fca6ea1SDimitry Andric       MachineInstr *SuccMI = SuccBBCopyInst[Key];
191*0fca6ea1SDimitry Andric       if (!isSafetoMove(SuccMI)) {
192*0fca6ea1SDimitry Andric         IsSafetoMove = false;
193*0fca6ea1SDimitry Andric         break;
194*0fca6ea1SDimitry Andric       }
195*0fca6ea1SDimitry Andric     }
196*0fca6ea1SDimitry Andric     // If we have come this far, this copy instruction can be safely
197*0fca6ea1SDimitry Andric     // moved to the predecessor basic block.
198*0fca6ea1SDimitry Andric     if (IsSafetoMove) {
199*0fca6ea1SDimitry Andric       LLVM_DEBUG(dbgs() << "\t\t Moving instr to BB#" << BB->getNumber() << ": "
200*0fca6ea1SDimitry Andric                         << MI << "\n");
201*0fca6ea1SDimitry Andric       moveCopyInstr(BB, Key, MI);
202*0fca6ea1SDimitry Andric       // Add my into BB copyMI list.
203*0fca6ea1SDimitry Andric       Changed = true;
204*0fca6ea1SDimitry Andric     }
205*0fca6ea1SDimitry Andric   }
206*0fca6ea1SDimitry Andric 
207*0fca6ea1SDimitry Andric #ifndef NDEBUG
208*0fca6ea1SDimitry Andric   auto &BBCopyInst = CopyMIList[BB->getNumber()];
209*0fca6ea1SDimitry Andric   for (auto II : BBCopyInst) {
210*0fca6ea1SDimitry Andric     MachineInstr *TempMI = II.getSecond();
211*0fca6ea1SDimitry Andric     LLVM_DEBUG(dbgs() << "\tIn the list: " << TempMI << "\n");
212*0fca6ea1SDimitry Andric   }
213*0fca6ea1SDimitry Andric #endif
214*0fca6ea1SDimitry Andric   return Changed;
215*0fca6ea1SDimitry Andric }
216*0fca6ea1SDimitry Andric 
217*0fca6ea1SDimitry Andric bool HexagonCopyHoisting::isSafetoMove(MachineInstr *CandMI) {
218*0fca6ea1SDimitry Andric   // Make sure that it's safe to move this 'copy' instruction to the predecessor
219*0fca6ea1SDimitry Andric   // basic block.
220*0fca6ea1SDimitry Andric   assert(CandMI->getOperand(0).isReg() && CandMI->getOperand(1).isReg());
221*0fca6ea1SDimitry Andric   Register DefR = CandMI->getOperand(0).getReg();
222*0fca6ea1SDimitry Andric   Register UseR = CandMI->getOperand(1).getReg();
223*0fca6ea1SDimitry Andric 
224*0fca6ea1SDimitry Andric   MachineBasicBlock *BB = CandMI->getParent();
225*0fca6ea1SDimitry Andric   // There should not be a def/use of DefR between the start of BB and CandMI.
226*0fca6ea1SDimitry Andric   MachineBasicBlock::iterator MII, MIE;
227*0fca6ea1SDimitry Andric   for (MII = BB->begin(), MIE = CandMI; MII != MIE; ++MII) {
228*0fca6ea1SDimitry Andric     MachineInstr *OtherMI = &*MII;
229*0fca6ea1SDimitry Andric     for (const MachineOperand &Mo : OtherMI->operands())
230*0fca6ea1SDimitry Andric       if (Mo.isReg() && Mo.getReg() == DefR)
231*0fca6ea1SDimitry Andric         return false;
232*0fca6ea1SDimitry Andric   }
233*0fca6ea1SDimitry Andric   // There should not be a def of UseR between the start of BB and CandMI.
234*0fca6ea1SDimitry Andric   for (MII = BB->begin(), MIE = CandMI; MII != MIE; ++MII) {
235*0fca6ea1SDimitry Andric     MachineInstr *OtherMI = &*MII;
236*0fca6ea1SDimitry Andric     for (const MachineOperand &Mo : OtherMI->operands())
237*0fca6ea1SDimitry Andric       if (Mo.isReg() && Mo.isDef() && Mo.getReg() == UseR)
238*0fca6ea1SDimitry Andric         return false;
239*0fca6ea1SDimitry Andric   }
240*0fca6ea1SDimitry Andric   return true;
241*0fca6ea1SDimitry Andric }
242*0fca6ea1SDimitry Andric 
243*0fca6ea1SDimitry Andric void HexagonCopyHoisting::moveCopyInstr(MachineBasicBlock *DestBB,
244*0fca6ea1SDimitry Andric                                         std::pair<Register, Register> Key,
245*0fca6ea1SDimitry Andric                                         MachineInstr *MI) {
246*0fca6ea1SDimitry Andric   MachineBasicBlock::iterator FirstTI = DestBB->getFirstTerminator();
247*0fca6ea1SDimitry Andric   assert(FirstTI != DestBB->end());
248*0fca6ea1SDimitry Andric 
249*0fca6ea1SDimitry Andric   DestBB->splice(FirstTI, MI->getParent(), MI);
250*0fca6ea1SDimitry Andric 
251*0fca6ea1SDimitry Andric   addMItoCopyList(MI);
252*0fca6ea1SDimitry Andric   for (auto I = ++(DestBB->succ_begin()), E = DestBB->succ_end(); I != E; ++I) {
253*0fca6ea1SDimitry Andric     MachineBasicBlock *SuccBB = *I;
254*0fca6ea1SDimitry Andric     auto &BBCopyInst = CopyMIList[SuccBB->getNumber()];
255*0fca6ea1SDimitry Andric     MachineInstr *SuccMI = BBCopyInst[Key];
256*0fca6ea1SDimitry Andric     SuccMI->eraseFromParent();
257*0fca6ea1SDimitry Andric     BBCopyInst.erase(Key);
258*0fca6ea1SDimitry Andric   }
259*0fca6ea1SDimitry Andric }
260*0fca6ea1SDimitry Andric 
261*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
262*0fca6ea1SDimitry Andric //                         Public Constructor Functions
263*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
264*0fca6ea1SDimitry Andric 
265*0fca6ea1SDimitry Andric INITIALIZE_PASS(HexagonCopyHoisting, "hexagon-move-phicopy",
266*0fca6ea1SDimitry Andric                 "Hexagon move phi copy", false, false)
267*0fca6ea1SDimitry Andric 
268*0fca6ea1SDimitry Andric FunctionPass *llvm::createHexagonCopyHoisting() {
269*0fca6ea1SDimitry Andric   return new HexagonCopyHoisting();
270*0fca6ea1SDimitry Andric }
271