1*9026518eSJames Molloy //=- MachineLoopUtils.cpp - Functions for manipulating loops ----------------=//
2*9026518eSJames Molloy //
3*9026518eSJames Molloy // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*9026518eSJames Molloy // See https://llvm.org/LICENSE.txt for license information.
5*9026518eSJames Molloy // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*9026518eSJames Molloy //
7*9026518eSJames Molloy //===----------------------------------------------------------------------===//
8*9026518eSJames Molloy 
9*9026518eSJames Molloy #include "llvm/CodeGen/MachineLoopUtils.h"
10*9026518eSJames Molloy #include "llvm/CodeGen/MachineBasicBlock.h"
11*9026518eSJames Molloy #include "llvm/CodeGen/MachineRegisterInfo.h"
12*9026518eSJames Molloy #include "llvm/CodeGen/TargetInstrInfo.h"
13*9026518eSJames Molloy using namespace llvm;
14*9026518eSJames Molloy 
15*9026518eSJames Molloy namespace {
16*9026518eSJames Molloy // MI's parent and BB are clones of each other. Find the equivalent copy of MI
17*9026518eSJames Molloy // in BB.
18*9026518eSJames Molloy MachineInstr &findEquivalentInstruction(MachineInstr &MI,
19*9026518eSJames Molloy                                         MachineBasicBlock *BB) {
20*9026518eSJames Molloy   MachineBasicBlock *PB = MI.getParent();
21*9026518eSJames Molloy   unsigned Offset = std::distance(PB->instr_begin(), MachineBasicBlock::instr_iterator(MI));
22*9026518eSJames Molloy   return *std::next(BB->instr_begin(), Offset);
23*9026518eSJames Molloy }
24*9026518eSJames Molloy } // namespace
25*9026518eSJames Molloy 
26*9026518eSJames Molloy MachineBasicBlock *llvm::PeelSingleBlockLoop(LoopPeelDirection Direction,
27*9026518eSJames Molloy                                              MachineBasicBlock *Loop,
28*9026518eSJames Molloy                                              MachineRegisterInfo &MRI,
29*9026518eSJames Molloy                                              const TargetInstrInfo *TII) {
30*9026518eSJames Molloy   MachineFunction &MF = *Loop->getParent();
31*9026518eSJames Molloy   MachineBasicBlock *Preheader = *Loop->pred_begin();
32*9026518eSJames Molloy   if (Preheader == Loop)
33*9026518eSJames Molloy     Preheader = *std::next(Loop->pred_begin());
34*9026518eSJames Molloy   MachineBasicBlock *Exit = *Loop->succ_begin();
35*9026518eSJames Molloy   if (Exit == Loop)
36*9026518eSJames Molloy     Exit = *std::next(Loop->succ_begin());
37*9026518eSJames Molloy 
38*9026518eSJames Molloy   MachineBasicBlock *NewBB = MF.CreateMachineBasicBlock(Loop->getBasicBlock());
39*9026518eSJames Molloy   if (Direction == LPD_Front)
40*9026518eSJames Molloy     MF.insert(Loop->getIterator(), NewBB);
41*9026518eSJames Molloy   else
42*9026518eSJames Molloy     MF.insert(std::next(Loop->getIterator()), NewBB);
43*9026518eSJames Molloy 
44*9026518eSJames Molloy   // FIXME: Add DenseMapInfo trait for Register so we can use it as a key.
45*9026518eSJames Molloy   DenseMap<unsigned, Register> Remaps;
46*9026518eSJames Molloy   auto InsertPt = NewBB->end();
47*9026518eSJames Molloy   for (MachineInstr &MI : *Loop) {
48*9026518eSJames Molloy     MachineInstr *NewMI = MF.CloneMachineInstr(&MI);
49*9026518eSJames Molloy     NewBB->insert(InsertPt, NewMI);
50*9026518eSJames Molloy     for (MachineOperand &MO : NewMI->defs()) {
51*9026518eSJames Molloy       Register OrigR = MO.getReg();
52*9026518eSJames Molloy       if (OrigR.isPhysical())
53*9026518eSJames Molloy         continue;
54*9026518eSJames Molloy       Register &R = Remaps[OrigR];
55*9026518eSJames Molloy       R = MRI.createVirtualRegister(MRI.getRegClass(OrigR));
56*9026518eSJames Molloy       MO.setReg(R);
57*9026518eSJames Molloy 
58*9026518eSJames Molloy       if (Direction == LPD_Back) {
59*9026518eSJames Molloy         // Replace all uses outside the original loop with the new register.
60*9026518eSJames Molloy         // FIXME: is the use_iterator stable enough to mutate register uses
61*9026518eSJames Molloy         // while iterating?
62*9026518eSJames Molloy         SmallVector<MachineOperand *, 4> Uses;
63*9026518eSJames Molloy         for (auto &Use : MRI.use_operands(OrigR))
64*9026518eSJames Molloy           if (Use.getParent()->getParent() != Loop)
65*9026518eSJames Molloy             Uses.push_back(&Use);
66*9026518eSJames Molloy         for (auto *Use : Uses) {
67*9026518eSJames Molloy           MRI.constrainRegClass(R, MRI.getRegClass(Use->getReg()));
68*9026518eSJames Molloy           Use->setReg(R);
69*9026518eSJames Molloy         }
70*9026518eSJames Molloy       }
71*9026518eSJames Molloy     }
72*9026518eSJames Molloy   }
73*9026518eSJames Molloy 
74*9026518eSJames Molloy   for (auto I = NewBB->getFirstNonPHI(); I != NewBB->end(); ++I)
75*9026518eSJames Molloy     for (MachineOperand &MO : I->uses())
76*9026518eSJames Molloy       if (MO.isReg() && Remaps.count(MO.getReg()))
77*9026518eSJames Molloy         MO.setReg(Remaps[MO.getReg()]);
78*9026518eSJames Molloy 
79*9026518eSJames Molloy   for (auto I = NewBB->begin(); I->isPHI(); ++I) {
80*9026518eSJames Molloy     MachineInstr &MI = *I;
81*9026518eSJames Molloy     unsigned LoopRegIdx = 3, InitRegIdx = 1;
82*9026518eSJames Molloy     if (MI.getOperand(2).getMBB() != Preheader)
83*9026518eSJames Molloy       std::swap(LoopRegIdx, InitRegIdx);
84*9026518eSJames Molloy     MachineInstr &OrigPhi = findEquivalentInstruction(MI, Loop);
85*9026518eSJames Molloy     assert(OrigPhi.isPHI());
86*9026518eSJames Molloy     if (Direction == LPD_Front) {
87*9026518eSJames Molloy       // When peeling front, we are only left with the initial value from the
88*9026518eSJames Molloy       // preheader.
89*9026518eSJames Molloy       Register R = MI.getOperand(LoopRegIdx).getReg();
90*9026518eSJames Molloy       if (Remaps.count(R))
91*9026518eSJames Molloy         R = Remaps[R];
92*9026518eSJames Molloy       OrigPhi.getOperand(InitRegIdx).setReg(R);
93*9026518eSJames Molloy       MI.RemoveOperand(LoopRegIdx + 1);
94*9026518eSJames Molloy       MI.RemoveOperand(LoopRegIdx + 0);
95*9026518eSJames Molloy     } else {
96*9026518eSJames Molloy       // When peeling back, the initial value is the loop-carried value from
97*9026518eSJames Molloy       // the original loop.
98*9026518eSJames Molloy       Register LoopReg = OrigPhi.getOperand(LoopRegIdx).getReg();
99*9026518eSJames Molloy       MI.getOperand(LoopRegIdx).setReg(LoopReg);
100*9026518eSJames Molloy       MI.RemoveOperand(InitRegIdx + 1);
101*9026518eSJames Molloy       MI.RemoveOperand(InitRegIdx + 0);
102*9026518eSJames Molloy     }
103*9026518eSJames Molloy   }
104*9026518eSJames Molloy 
105*9026518eSJames Molloy   DebugLoc DL;
106*9026518eSJames Molloy   if (Direction == LPD_Front) {
107*9026518eSJames Molloy     Preheader->replaceSuccessor(Loop, NewBB);
108*9026518eSJames Molloy     NewBB->addSuccessor(Loop);
109*9026518eSJames Molloy     Loop->replacePhiUsesWith(Preheader, NewBB);
110*9026518eSJames Molloy     if (TII->removeBranch(*Preheader) > 0)
111*9026518eSJames Molloy       TII->insertBranch(*Preheader, NewBB, nullptr, {}, DL);
112*9026518eSJames Molloy     TII->removeBranch(*NewBB);
113*9026518eSJames Molloy     TII->insertBranch(*NewBB, Loop, nullptr, {}, DL);
114*9026518eSJames Molloy   } else {
115*9026518eSJames Molloy     Loop->replaceSuccessor(Exit, NewBB);
116*9026518eSJames Molloy     Exit->replacePhiUsesWith(Loop, NewBB);
117*9026518eSJames Molloy     NewBB->addSuccessor(Exit);
118*9026518eSJames Molloy 
119*9026518eSJames Molloy     MachineBasicBlock *TBB = nullptr, *FBB = nullptr;
120*9026518eSJames Molloy     SmallVector<MachineOperand, 4> Cond;
121*9026518eSJames Molloy     bool CanAnalyzeBr = !TII->analyzeBranch(*Loop, TBB, FBB, Cond);
122*9026518eSJames Molloy     (void)CanAnalyzeBr;
123*9026518eSJames Molloy     assert(CanAnalyzeBr && "Must be able to analyze the loop branch!");
124*9026518eSJames Molloy     TII->removeBranch(*Loop);
125*9026518eSJames Molloy     TII->insertBranch(*Loop, TBB == Exit ? NewBB : TBB,
126*9026518eSJames Molloy                       FBB == Exit ? NewBB : FBB, Cond, DL);
127*9026518eSJames Molloy     if (TII->removeBranch(*NewBB) > 0)
128*9026518eSJames Molloy       TII->insertBranch(*NewBB, Exit, nullptr, {}, DL);
129*9026518eSJames Molloy   }
130*9026518eSJames Molloy 
131*9026518eSJames Molloy   return NewBB;
132*9026518eSJames Molloy }
133