19026518eSJames Molloy //=- MachineLoopUtils.cpp - Functions for manipulating loops ----------------=//
29026518eSJames Molloy //
39026518eSJames Molloy // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
49026518eSJames Molloy // See https://llvm.org/LICENSE.txt for license information.
59026518eSJames Molloy // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
69026518eSJames Molloy //
79026518eSJames Molloy //===----------------------------------------------------------------------===//
89026518eSJames Molloy 
9d97cf1f8SSjoerd Meijer #include "llvm/CodeGen/MachineLoopInfo.h"
109026518eSJames Molloy #include "llvm/CodeGen/MachineLoopUtils.h"
119026518eSJames Molloy #include "llvm/CodeGen/MachineBasicBlock.h"
129026518eSJames Molloy #include "llvm/CodeGen/MachineRegisterInfo.h"
139026518eSJames Molloy #include "llvm/CodeGen/TargetInstrInfo.h"
149026518eSJames Molloy using namespace llvm;
159026518eSJames Molloy 
169026518eSJames Molloy namespace {
179026518eSJames Molloy // MI's parent and BB are clones of each other. Find the equivalent copy of MI
189026518eSJames Molloy // in BB.
199026518eSJames Molloy MachineInstr &findEquivalentInstruction(MachineInstr &MI,
209026518eSJames Molloy                                         MachineBasicBlock *BB) {
219026518eSJames Molloy   MachineBasicBlock *PB = MI.getParent();
229026518eSJames Molloy   unsigned Offset = std::distance(PB->instr_begin(), MachineBasicBlock::instr_iterator(MI));
239026518eSJames Molloy   return *std::next(BB->instr_begin(), Offset);
249026518eSJames Molloy }
259026518eSJames Molloy } // namespace
269026518eSJames Molloy 
279026518eSJames Molloy MachineBasicBlock *llvm::PeelSingleBlockLoop(LoopPeelDirection Direction,
289026518eSJames Molloy                                              MachineBasicBlock *Loop,
299026518eSJames Molloy                                              MachineRegisterInfo &MRI,
309026518eSJames Molloy                                              const TargetInstrInfo *TII) {
319026518eSJames Molloy   MachineFunction &MF = *Loop->getParent();
329026518eSJames Molloy   MachineBasicBlock *Preheader = *Loop->pred_begin();
339026518eSJames Molloy   if (Preheader == Loop)
349026518eSJames Molloy     Preheader = *std::next(Loop->pred_begin());
359026518eSJames Molloy   MachineBasicBlock *Exit = *Loop->succ_begin();
369026518eSJames Molloy   if (Exit == Loop)
379026518eSJames Molloy     Exit = *std::next(Loop->succ_begin());
389026518eSJames Molloy 
399026518eSJames Molloy   MachineBasicBlock *NewBB = MF.CreateMachineBasicBlock(Loop->getBasicBlock());
409026518eSJames Molloy   if (Direction == LPD_Front)
419026518eSJames Molloy     MF.insert(Loop->getIterator(), NewBB);
429026518eSJames Molloy   else
439026518eSJames Molloy     MF.insert(std::next(Loop->getIterator()), NewBB);
449026518eSJames Molloy 
45*bf730e16SJay Foad   DenseMap<Register, Register> Remaps;
469026518eSJames Molloy   auto InsertPt = NewBB->end();
479026518eSJames Molloy   for (MachineInstr &MI : *Loop) {
489026518eSJames Molloy     MachineInstr *NewMI = MF.CloneMachineInstr(&MI);
499026518eSJames Molloy     NewBB->insert(InsertPt, NewMI);
509026518eSJames Molloy     for (MachineOperand &MO : NewMI->defs()) {
519026518eSJames Molloy       Register OrigR = MO.getReg();
529026518eSJames Molloy       if (OrigR.isPhysical())
539026518eSJames Molloy         continue;
549026518eSJames Molloy       Register &R = Remaps[OrigR];
559026518eSJames Molloy       R = MRI.createVirtualRegister(MRI.getRegClass(OrigR));
569026518eSJames Molloy       MO.setReg(R);
579026518eSJames Molloy 
589026518eSJames Molloy       if (Direction == LPD_Back) {
599026518eSJames Molloy         // Replace all uses outside the original loop with the new register.
609026518eSJames Molloy         // FIXME: is the use_iterator stable enough to mutate register uses
619026518eSJames Molloy         // while iterating?
629026518eSJames Molloy         SmallVector<MachineOperand *, 4> Uses;
639026518eSJames Molloy         for (auto &Use : MRI.use_operands(OrigR))
649026518eSJames Molloy           if (Use.getParent()->getParent() != Loop)
659026518eSJames Molloy             Uses.push_back(&Use);
669026518eSJames Molloy         for (auto *Use : Uses) {
679026518eSJames Molloy           MRI.constrainRegClass(R, MRI.getRegClass(Use->getReg()));
689026518eSJames Molloy           Use->setReg(R);
699026518eSJames Molloy         }
709026518eSJames Molloy       }
719026518eSJames Molloy     }
729026518eSJames Molloy   }
739026518eSJames Molloy 
749026518eSJames Molloy   for (auto I = NewBB->getFirstNonPHI(); I != NewBB->end(); ++I)
759026518eSJames Molloy     for (MachineOperand &MO : I->uses())
769026518eSJames Molloy       if (MO.isReg() && Remaps.count(MO.getReg()))
779026518eSJames Molloy         MO.setReg(Remaps[MO.getReg()]);
789026518eSJames Molloy 
799026518eSJames Molloy   for (auto I = NewBB->begin(); I->isPHI(); ++I) {
809026518eSJames Molloy     MachineInstr &MI = *I;
819026518eSJames Molloy     unsigned LoopRegIdx = 3, InitRegIdx = 1;
829026518eSJames Molloy     if (MI.getOperand(2).getMBB() != Preheader)
839026518eSJames Molloy       std::swap(LoopRegIdx, InitRegIdx);
849026518eSJames Molloy     MachineInstr &OrigPhi = findEquivalentInstruction(MI, Loop);
859026518eSJames Molloy     assert(OrigPhi.isPHI());
869026518eSJames Molloy     if (Direction == LPD_Front) {
879026518eSJames Molloy       // When peeling front, we are only left with the initial value from the
889026518eSJames Molloy       // preheader.
899026518eSJames Molloy       Register R = MI.getOperand(LoopRegIdx).getReg();
909026518eSJames Molloy       if (Remaps.count(R))
919026518eSJames Molloy         R = Remaps[R];
929026518eSJames Molloy       OrigPhi.getOperand(InitRegIdx).setReg(R);
939026518eSJames Molloy       MI.RemoveOperand(LoopRegIdx + 1);
949026518eSJames Molloy       MI.RemoveOperand(LoopRegIdx + 0);
959026518eSJames Molloy     } else {
969026518eSJames Molloy       // When peeling back, the initial value is the loop-carried value from
979026518eSJames Molloy       // the original loop.
989026518eSJames Molloy       Register LoopReg = OrigPhi.getOperand(LoopRegIdx).getReg();
999026518eSJames Molloy       MI.getOperand(LoopRegIdx).setReg(LoopReg);
1009026518eSJames Molloy       MI.RemoveOperand(InitRegIdx + 1);
1019026518eSJames Molloy       MI.RemoveOperand(InitRegIdx + 0);
1029026518eSJames Molloy     }
1039026518eSJames Molloy   }
1049026518eSJames Molloy 
1059026518eSJames Molloy   DebugLoc DL;
1069026518eSJames Molloy   if (Direction == LPD_Front) {
1079026518eSJames Molloy     Preheader->replaceSuccessor(Loop, NewBB);
1089026518eSJames Molloy     NewBB->addSuccessor(Loop);
1099026518eSJames Molloy     Loop->replacePhiUsesWith(Preheader, NewBB);
1109026518eSJames Molloy     if (TII->removeBranch(*Preheader) > 0)
1119026518eSJames Molloy       TII->insertBranch(*Preheader, NewBB, nullptr, {}, DL);
1129026518eSJames Molloy     TII->removeBranch(*NewBB);
1139026518eSJames Molloy     TII->insertBranch(*NewBB, Loop, nullptr, {}, DL);
1149026518eSJames Molloy   } else {
1159026518eSJames Molloy     Loop->replaceSuccessor(Exit, NewBB);
1169026518eSJames Molloy     Exit->replacePhiUsesWith(Loop, NewBB);
1179026518eSJames Molloy     NewBB->addSuccessor(Exit);
1189026518eSJames Molloy 
1199026518eSJames Molloy     MachineBasicBlock *TBB = nullptr, *FBB = nullptr;
1209026518eSJames Molloy     SmallVector<MachineOperand, 4> Cond;
1219026518eSJames Molloy     bool CanAnalyzeBr = !TII->analyzeBranch(*Loop, TBB, FBB, Cond);
1229026518eSJames Molloy     (void)CanAnalyzeBr;
1239026518eSJames Molloy     assert(CanAnalyzeBr && "Must be able to analyze the loop branch!");
1249026518eSJames Molloy     TII->removeBranch(*Loop);
1259026518eSJames Molloy     TII->insertBranch(*Loop, TBB == Exit ? NewBB : TBB,
1269026518eSJames Molloy                       FBB == Exit ? NewBB : FBB, Cond, DL);
1279026518eSJames Molloy     if (TII->removeBranch(*NewBB) > 0)
1289026518eSJames Molloy       TII->insertBranch(*NewBB, Exit, nullptr, {}, DL);
1299026518eSJames Molloy   }
1309026518eSJames Molloy 
1319026518eSJames Molloy   return NewBB;
1329026518eSJames Molloy }
133d97cf1f8SSjoerd Meijer 
134d97cf1f8SSjoerd Meijer bool llvm::isRegLiveInExitBlocks(MachineLoop *Loop, int PhysReg) {
135d97cf1f8SSjoerd Meijer   SmallVector<MachineBasicBlock *, 4> ExitBlocks;
136d97cf1f8SSjoerd Meijer   Loop->getExitBlocks(ExitBlocks);
137d97cf1f8SSjoerd Meijer 
138d97cf1f8SSjoerd Meijer   for (auto *MBB : ExitBlocks)
139d97cf1f8SSjoerd Meijer     if (MBB->isLiveIn(PhysReg))
140d97cf1f8SSjoerd Meijer       return true;
141d97cf1f8SSjoerd Meijer 
142d97cf1f8SSjoerd Meijer   return false;
143d97cf1f8SSjoerd Meijer }
144