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