1*81ad6265SDimitry Andric //=- RISCVRedundantCopyElimination.cpp - Remove useless copy for RISCV ------=// 2*81ad6265SDimitry Andric // 3*81ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*81ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*81ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*81ad6265SDimitry Andric // 7*81ad6265SDimitry Andric //===----------------------------------------------------------------------===// 8*81ad6265SDimitry Andric // 9*81ad6265SDimitry Andric // This pass removes unnecessary zero copies in BBs that are targets of 10*81ad6265SDimitry Andric // beqz/bnez instructions. For instance, the copy instruction in the code below 11*81ad6265SDimitry Andric // can be removed because the beqz jumps to BB#2 when a0 is zero. 12*81ad6265SDimitry Andric // BB#1: 13*81ad6265SDimitry Andric // beqz %a0, <BB#2> 14*81ad6265SDimitry Andric // BB#2: 15*81ad6265SDimitry Andric // %a0 = COPY %x0 16*81ad6265SDimitry Andric // This pass should be run after register allocation. 17*81ad6265SDimitry Andric // 18*81ad6265SDimitry Andric // This pass is based on the earliest versions of 19*81ad6265SDimitry Andric // AArch64RedundantCopyElimination. 20*81ad6265SDimitry Andric // 21*81ad6265SDimitry Andric // FIXME: Support compares with constants other than zero? This is harder to 22*81ad6265SDimitry Andric // do on RISC-V since branches can't have immediates. 23*81ad6265SDimitry Andric // 24*81ad6265SDimitry Andric //===----------------------------------------------------------------------===// 25*81ad6265SDimitry Andric 26*81ad6265SDimitry Andric #include "RISCV.h" 27*81ad6265SDimitry Andric #include "llvm/ADT/Statistic.h" 28*81ad6265SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 29*81ad6265SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 30*81ad6265SDimitry Andric #include "llvm/Support/Debug.h" 31*81ad6265SDimitry Andric 32*81ad6265SDimitry Andric using namespace llvm; 33*81ad6265SDimitry Andric 34*81ad6265SDimitry Andric #define DEBUG_TYPE "riscv-copyelim" 35*81ad6265SDimitry Andric 36*81ad6265SDimitry Andric STATISTIC(NumCopiesRemoved, "Number of copies removed."); 37*81ad6265SDimitry Andric 38*81ad6265SDimitry Andric namespace { 39*81ad6265SDimitry Andric class RISCVRedundantCopyElimination : public MachineFunctionPass { 40*81ad6265SDimitry Andric const MachineRegisterInfo *MRI; 41*81ad6265SDimitry Andric const TargetRegisterInfo *TRI; 42*81ad6265SDimitry Andric 43*81ad6265SDimitry Andric public: 44*81ad6265SDimitry Andric static char ID; 45*81ad6265SDimitry Andric RISCVRedundantCopyElimination() : MachineFunctionPass(ID) { 46*81ad6265SDimitry Andric initializeRISCVRedundantCopyEliminationPass( 47*81ad6265SDimitry Andric *PassRegistry::getPassRegistry()); 48*81ad6265SDimitry Andric } 49*81ad6265SDimitry Andric 50*81ad6265SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 51*81ad6265SDimitry Andric MachineFunctionProperties getRequiredProperties() const override { 52*81ad6265SDimitry Andric return MachineFunctionProperties().set( 53*81ad6265SDimitry Andric MachineFunctionProperties::Property::NoVRegs); 54*81ad6265SDimitry Andric } 55*81ad6265SDimitry Andric 56*81ad6265SDimitry Andric StringRef getPassName() const override { 57*81ad6265SDimitry Andric return "RISCV Redundant Copy Elimination"; 58*81ad6265SDimitry Andric } 59*81ad6265SDimitry Andric 60*81ad6265SDimitry Andric private: 61*81ad6265SDimitry Andric bool optimizeBlock(MachineBasicBlock &MBB); 62*81ad6265SDimitry Andric }; 63*81ad6265SDimitry Andric 64*81ad6265SDimitry Andric } // end anonymous namespace 65*81ad6265SDimitry Andric 66*81ad6265SDimitry Andric char RISCVRedundantCopyElimination::ID = 0; 67*81ad6265SDimitry Andric 68*81ad6265SDimitry Andric INITIALIZE_PASS(RISCVRedundantCopyElimination, "riscv-copyelim", 69*81ad6265SDimitry Andric "RISCV redundant copy elimination pass", false, false) 70*81ad6265SDimitry Andric 71*81ad6265SDimitry Andric static bool guaranteesZeroRegInBlock(const MachineInstr &MI, 72*81ad6265SDimitry Andric const MachineBasicBlock &MBB) { 73*81ad6265SDimitry Andric unsigned Opc = MI.getOpcode(); 74*81ad6265SDimitry Andric if (Opc == RISCV::BEQ && MI.getOperand(1).getReg() == RISCV::X0 && 75*81ad6265SDimitry Andric &MBB == MI.getOperand(2).getMBB()) 76*81ad6265SDimitry Andric return true; 77*81ad6265SDimitry Andric if (Opc == RISCV::BNE && MI.getOperand(1).getReg() == RISCV::X0 && 78*81ad6265SDimitry Andric &MBB != MI.getOperand(2).getMBB()) 79*81ad6265SDimitry Andric return true; 80*81ad6265SDimitry Andric 81*81ad6265SDimitry Andric return false; 82*81ad6265SDimitry Andric } 83*81ad6265SDimitry Andric 84*81ad6265SDimitry Andric bool RISCVRedundantCopyElimination::optimizeBlock(MachineBasicBlock &MBB) { 85*81ad6265SDimitry Andric // Check if the current basic block has a single predecessor. 86*81ad6265SDimitry Andric if (MBB.pred_size() != 1) 87*81ad6265SDimitry Andric return false; 88*81ad6265SDimitry Andric 89*81ad6265SDimitry Andric // Check if the predecessor has two successors, implying the block ends in a 90*81ad6265SDimitry Andric // conditional branch. 91*81ad6265SDimitry Andric MachineBasicBlock *PredMBB = *MBB.pred_begin(); 92*81ad6265SDimitry Andric if (PredMBB->succ_size() != 2) 93*81ad6265SDimitry Andric return false; 94*81ad6265SDimitry Andric 95*81ad6265SDimitry Andric MachineBasicBlock::iterator CondBr = PredMBB->getLastNonDebugInstr(); 96*81ad6265SDimitry Andric if (CondBr == PredMBB->end()) 97*81ad6265SDimitry Andric return false; 98*81ad6265SDimitry Andric 99*81ad6265SDimitry Andric while (true) { 100*81ad6265SDimitry Andric // If we run out of terminators, give up. 101*81ad6265SDimitry Andric if (!CondBr->isTerminator()) 102*81ad6265SDimitry Andric return false; 103*81ad6265SDimitry Andric // If we found a branch with X0, stop searching and try to remove copies. 104*81ad6265SDimitry Andric // TODO: Handle multiple branches with different registers. 105*81ad6265SDimitry Andric if (guaranteesZeroRegInBlock(*CondBr, MBB)) 106*81ad6265SDimitry Andric break; 107*81ad6265SDimitry Andric // If we reached the beginning of the basic block, give up. 108*81ad6265SDimitry Andric if (CondBr == PredMBB->begin()) 109*81ad6265SDimitry Andric return false; 110*81ad6265SDimitry Andric --CondBr; 111*81ad6265SDimitry Andric } 112*81ad6265SDimitry Andric 113*81ad6265SDimitry Andric Register TargetReg = CondBr->getOperand(0).getReg(); 114*81ad6265SDimitry Andric if (!TargetReg) 115*81ad6265SDimitry Andric return false; 116*81ad6265SDimitry Andric 117*81ad6265SDimitry Andric bool Changed = false; 118*81ad6265SDimitry Andric MachineBasicBlock::iterator LastChange = MBB.begin(); 119*81ad6265SDimitry Andric // Remove redundant Copy instructions unless TargetReg is modified. 120*81ad6265SDimitry Andric for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); I != E;) { 121*81ad6265SDimitry Andric MachineInstr *MI = &*I; 122*81ad6265SDimitry Andric ++I; 123*81ad6265SDimitry Andric if (MI->isCopy() && MI->getOperand(0).isReg() && 124*81ad6265SDimitry Andric MI->getOperand(1).isReg()) { 125*81ad6265SDimitry Andric Register DefReg = MI->getOperand(0).getReg(); 126*81ad6265SDimitry Andric Register SrcReg = MI->getOperand(1).getReg(); 127*81ad6265SDimitry Andric 128*81ad6265SDimitry Andric if (SrcReg == RISCV::X0 && !MRI->isReserved(DefReg) && 129*81ad6265SDimitry Andric TargetReg == DefReg) { 130*81ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Remove redundant Copy : "); 131*81ad6265SDimitry Andric LLVM_DEBUG(MI->print(dbgs())); 132*81ad6265SDimitry Andric 133*81ad6265SDimitry Andric MI->eraseFromParent(); 134*81ad6265SDimitry Andric Changed = true; 135*81ad6265SDimitry Andric LastChange = I; 136*81ad6265SDimitry Andric ++NumCopiesRemoved; 137*81ad6265SDimitry Andric continue; 138*81ad6265SDimitry Andric } 139*81ad6265SDimitry Andric } 140*81ad6265SDimitry Andric 141*81ad6265SDimitry Andric if (MI->modifiesRegister(TargetReg, TRI)) 142*81ad6265SDimitry Andric break; 143*81ad6265SDimitry Andric } 144*81ad6265SDimitry Andric 145*81ad6265SDimitry Andric if (!Changed) 146*81ad6265SDimitry Andric return false; 147*81ad6265SDimitry Andric 148*81ad6265SDimitry Andric // Otherwise, we have to fixup the use-def chain, starting with the 149*81ad6265SDimitry Andric // BEQ/BNE. Conservatively mark as much as we can live. 150*81ad6265SDimitry Andric CondBr->clearRegisterKills(TargetReg, TRI); 151*81ad6265SDimitry Andric 152*81ad6265SDimitry Andric // Add newly used reg to the block's live-in list if it isn't there already. 153*81ad6265SDimitry Andric if (!MBB.isLiveIn(TargetReg)) 154*81ad6265SDimitry Andric MBB.addLiveIn(TargetReg); 155*81ad6265SDimitry Andric 156*81ad6265SDimitry Andric // Clear any kills of TargetReg between CondBr and the last removed COPY. 157*81ad6265SDimitry Andric for (MachineInstr &MMI : make_range(MBB.begin(), LastChange)) 158*81ad6265SDimitry Andric MMI.clearRegisterKills(TargetReg, TRI); 159*81ad6265SDimitry Andric 160*81ad6265SDimitry Andric return true; 161*81ad6265SDimitry Andric } 162*81ad6265SDimitry Andric 163*81ad6265SDimitry Andric bool RISCVRedundantCopyElimination::runOnMachineFunction(MachineFunction &MF) { 164*81ad6265SDimitry Andric if (skipFunction(MF.getFunction())) 165*81ad6265SDimitry Andric return false; 166*81ad6265SDimitry Andric 167*81ad6265SDimitry Andric TRI = MF.getSubtarget().getRegisterInfo(); 168*81ad6265SDimitry Andric MRI = &MF.getRegInfo(); 169*81ad6265SDimitry Andric 170*81ad6265SDimitry Andric bool Changed = false; 171*81ad6265SDimitry Andric for (MachineBasicBlock &MBB : MF) 172*81ad6265SDimitry Andric Changed |= optimizeBlock(MBB); 173*81ad6265SDimitry Andric 174*81ad6265SDimitry Andric return Changed; 175*81ad6265SDimitry Andric } 176*81ad6265SDimitry Andric 177*81ad6265SDimitry Andric FunctionPass *llvm::createRISCVRedundantCopyEliminationPass() { 178*81ad6265SDimitry Andric return new RISCVRedundantCopyElimination(); 179*81ad6265SDimitry Andric } 180