| //=- MachineLoopUtils.cpp - Functions for manipulating loops ----------------=// | 
 | // | 
 | // 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 | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | #include "llvm/CodeGen/MachineLoopInfo.h" | 
 | #include "llvm/CodeGen/MachineLoopUtils.h" | 
 | #include "llvm/CodeGen/MachineBasicBlock.h" | 
 | #include "llvm/CodeGen/MachineRegisterInfo.h" | 
 | #include "llvm/CodeGen/TargetInstrInfo.h" | 
 | using namespace llvm; | 
 |  | 
 | namespace { | 
 | // MI's parent and BB are clones of each other. Find the equivalent copy of MI | 
 | // in BB. | 
 | MachineInstr &findEquivalentInstruction(MachineInstr &MI, | 
 |                                         MachineBasicBlock *BB) { | 
 |   MachineBasicBlock *PB = MI.getParent(); | 
 |   unsigned Offset = std::distance(PB->instr_begin(), MachineBasicBlock::instr_iterator(MI)); | 
 |   return *std::next(BB->instr_begin(), Offset); | 
 | } | 
 | } // namespace | 
 |  | 
 | MachineBasicBlock *llvm::PeelSingleBlockLoop(LoopPeelDirection Direction, | 
 |                                              MachineBasicBlock *Loop, | 
 |                                              MachineRegisterInfo &MRI, | 
 |                                              const TargetInstrInfo *TII) { | 
 |   MachineFunction &MF = *Loop->getParent(); | 
 |   MachineBasicBlock *Preheader = *Loop->pred_begin(); | 
 |   if (Preheader == Loop) | 
 |     Preheader = *std::next(Loop->pred_begin()); | 
 |   MachineBasicBlock *Exit = *Loop->succ_begin(); | 
 |   if (Exit == Loop) | 
 |     Exit = *std::next(Loop->succ_begin()); | 
 |  | 
 |   MachineBasicBlock *NewBB = MF.CreateMachineBasicBlock(Loop->getBasicBlock()); | 
 |   if (Direction == LPD_Front) | 
 |     MF.insert(Loop->getIterator(), NewBB); | 
 |   else | 
 |     MF.insert(std::next(Loop->getIterator()), NewBB); | 
 |  | 
 |   // FIXME: Add DenseMapInfo trait for Register so we can use it as a key. | 
 |   DenseMap<unsigned, Register> Remaps; | 
 |   auto InsertPt = NewBB->end(); | 
 |   for (MachineInstr &MI : *Loop) { | 
 |     MachineInstr *NewMI = MF.CloneMachineInstr(&MI); | 
 |     NewBB->insert(InsertPt, NewMI); | 
 |     for (MachineOperand &MO : NewMI->defs()) { | 
 |       Register OrigR = MO.getReg(); | 
 |       if (OrigR.isPhysical()) | 
 |         continue; | 
 |       Register &R = Remaps[OrigR]; | 
 |       R = MRI.createVirtualRegister(MRI.getRegClass(OrigR)); | 
 |       MO.setReg(R); | 
 |  | 
 |       if (Direction == LPD_Back) { | 
 |         // Replace all uses outside the original loop with the new register. | 
 |         // FIXME: is the use_iterator stable enough to mutate register uses | 
 |         // while iterating? | 
 |         SmallVector<MachineOperand *, 4> Uses; | 
 |         for (auto &Use : MRI.use_operands(OrigR)) | 
 |           if (Use.getParent()->getParent() != Loop) | 
 |             Uses.push_back(&Use); | 
 |         for (auto *Use : Uses) { | 
 |           MRI.constrainRegClass(R, MRI.getRegClass(Use->getReg())); | 
 |           Use->setReg(R); | 
 |         } | 
 |       } | 
 |     } | 
 |   } | 
 |  | 
 |   for (auto I = NewBB->getFirstNonPHI(); I != NewBB->end(); ++I) | 
 |     for (MachineOperand &MO : I->uses()) | 
 |       if (MO.isReg() && Remaps.count(MO.getReg())) | 
 |         MO.setReg(Remaps[MO.getReg()]); | 
 |  | 
 |   for (auto I = NewBB->begin(); I->isPHI(); ++I) { | 
 |     MachineInstr &MI = *I; | 
 |     unsigned LoopRegIdx = 3, InitRegIdx = 1; | 
 |     if (MI.getOperand(2).getMBB() != Preheader) | 
 |       std::swap(LoopRegIdx, InitRegIdx); | 
 |     MachineInstr &OrigPhi = findEquivalentInstruction(MI, Loop); | 
 |     assert(OrigPhi.isPHI()); | 
 |     if (Direction == LPD_Front) { | 
 |       // When peeling front, we are only left with the initial value from the | 
 |       // preheader. | 
 |       Register R = MI.getOperand(LoopRegIdx).getReg(); | 
 |       if (Remaps.count(R)) | 
 |         R = Remaps[R]; | 
 |       OrigPhi.getOperand(InitRegIdx).setReg(R); | 
 |       MI.RemoveOperand(LoopRegIdx + 1); | 
 |       MI.RemoveOperand(LoopRegIdx + 0); | 
 |     } else { | 
 |       // When peeling back, the initial value is the loop-carried value from | 
 |       // the original loop. | 
 |       Register LoopReg = OrigPhi.getOperand(LoopRegIdx).getReg(); | 
 |       MI.getOperand(LoopRegIdx).setReg(LoopReg); | 
 |       MI.RemoveOperand(InitRegIdx + 1); | 
 |       MI.RemoveOperand(InitRegIdx + 0); | 
 |     } | 
 |   } | 
 |  | 
 |   DebugLoc DL; | 
 |   if (Direction == LPD_Front) { | 
 |     Preheader->replaceSuccessor(Loop, NewBB); | 
 |     NewBB->addSuccessor(Loop); | 
 |     Loop->replacePhiUsesWith(Preheader, NewBB); | 
 |     if (TII->removeBranch(*Preheader) > 0) | 
 |       TII->insertBranch(*Preheader, NewBB, nullptr, {}, DL); | 
 |     TII->removeBranch(*NewBB); | 
 |     TII->insertBranch(*NewBB, Loop, nullptr, {}, DL); | 
 |   } else { | 
 |     Loop->replaceSuccessor(Exit, NewBB); | 
 |     Exit->replacePhiUsesWith(Loop, NewBB); | 
 |     NewBB->addSuccessor(Exit); | 
 |  | 
 |     MachineBasicBlock *TBB = nullptr, *FBB = nullptr; | 
 |     SmallVector<MachineOperand, 4> Cond; | 
 |     bool CanAnalyzeBr = !TII->analyzeBranch(*Loop, TBB, FBB, Cond); | 
 |     (void)CanAnalyzeBr; | 
 |     assert(CanAnalyzeBr && "Must be able to analyze the loop branch!"); | 
 |     TII->removeBranch(*Loop); | 
 |     TII->insertBranch(*Loop, TBB == Exit ? NewBB : TBB, | 
 |                       FBB == Exit ? NewBB : FBB, Cond, DL); | 
 |     if (TII->removeBranch(*NewBB) > 0) | 
 |       TII->insertBranch(*NewBB, Exit, nullptr, {}, DL); | 
 |   } | 
 |  | 
 |   return NewBB; | 
 | } | 
 |  | 
 | bool llvm::isRegLiveInExitBlocks(MachineLoop *Loop, int PhysReg) { | 
 |   SmallVector<MachineBasicBlock *, 4> ExitBlocks; | 
 |   Loop->getExitBlocks(ExitBlocks); | 
 |  | 
 |   for (auto *MBB : ExitBlocks) | 
 |     if (MBB->isLiveIn(PhysReg)) | 
 |       return true; | 
 |  | 
 |   return false; | 
 | } |