106c3fb27SDimitry Andric //=- RISCVRedundantCopyElimination.cpp - Remove useless copy for RISC-V -----=// 281ad6265SDimitry Andric // 381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 681ad6265SDimitry Andric // 781ad6265SDimitry Andric //===----------------------------------------------------------------------===// 881ad6265SDimitry Andric // 981ad6265SDimitry Andric // This pass removes unnecessary zero copies in BBs that are targets of 1081ad6265SDimitry Andric // beqz/bnez instructions. For instance, the copy instruction in the code below 1181ad6265SDimitry Andric // can be removed because the beqz jumps to BB#2 when a0 is zero. 1281ad6265SDimitry Andric // BB#1: 1381ad6265SDimitry Andric // beqz %a0, <BB#2> 1481ad6265SDimitry Andric // BB#2: 1581ad6265SDimitry Andric // %a0 = COPY %x0 1681ad6265SDimitry Andric // This pass should be run after register allocation. 1781ad6265SDimitry Andric // 1881ad6265SDimitry Andric // This pass is based on the earliest versions of 1981ad6265SDimitry Andric // AArch64RedundantCopyElimination. 2081ad6265SDimitry Andric // 2181ad6265SDimitry Andric // FIXME: Support compares with constants other than zero? This is harder to 2281ad6265SDimitry Andric // do on RISC-V since branches can't have immediates. 2381ad6265SDimitry Andric // 2481ad6265SDimitry Andric //===----------------------------------------------------------------------===// 2581ad6265SDimitry Andric 2681ad6265SDimitry Andric #include "RISCV.h" 27bdd1243dSDimitry Andric #include "RISCVInstrInfo.h" 2881ad6265SDimitry Andric #include "llvm/ADT/Statistic.h" 2981ad6265SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 3081ad6265SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 3181ad6265SDimitry Andric #include "llvm/Support/Debug.h" 3281ad6265SDimitry Andric 3381ad6265SDimitry Andric using namespace llvm; 3481ad6265SDimitry Andric 3581ad6265SDimitry Andric #define DEBUG_TYPE "riscv-copyelim" 3681ad6265SDimitry Andric 3781ad6265SDimitry Andric STATISTIC(NumCopiesRemoved, "Number of copies removed."); 3881ad6265SDimitry Andric 3981ad6265SDimitry Andric namespace { 4081ad6265SDimitry Andric class RISCVRedundantCopyElimination : public MachineFunctionPass { 4181ad6265SDimitry Andric const MachineRegisterInfo *MRI; 4281ad6265SDimitry Andric const TargetRegisterInfo *TRI; 43bdd1243dSDimitry Andric const TargetInstrInfo *TII; 4481ad6265SDimitry Andric 4581ad6265SDimitry Andric public: 4681ad6265SDimitry Andric static char ID; 4781ad6265SDimitry Andric RISCVRedundantCopyElimination() : MachineFunctionPass(ID) { 4881ad6265SDimitry Andric initializeRISCVRedundantCopyEliminationPass( 4981ad6265SDimitry Andric *PassRegistry::getPassRegistry()); 5081ad6265SDimitry Andric } 5181ad6265SDimitry Andric 5281ad6265SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 5381ad6265SDimitry Andric MachineFunctionProperties getRequiredProperties() const override { 5481ad6265SDimitry Andric return MachineFunctionProperties().set( 5581ad6265SDimitry Andric MachineFunctionProperties::Property::NoVRegs); 5681ad6265SDimitry Andric } 5781ad6265SDimitry Andric 5881ad6265SDimitry Andric StringRef getPassName() const override { 5906c3fb27SDimitry Andric return "RISC-V Redundant Copy Elimination"; 6081ad6265SDimitry Andric } 6181ad6265SDimitry Andric 6281ad6265SDimitry Andric private: 6381ad6265SDimitry Andric bool optimizeBlock(MachineBasicBlock &MBB); 6481ad6265SDimitry Andric }; 6581ad6265SDimitry Andric 6681ad6265SDimitry Andric } // end anonymous namespace 6781ad6265SDimitry Andric 6881ad6265SDimitry Andric char RISCVRedundantCopyElimination::ID = 0; 6981ad6265SDimitry Andric 7081ad6265SDimitry Andric INITIALIZE_PASS(RISCVRedundantCopyElimination, "riscv-copyelim", 7106c3fb27SDimitry Andric "RISC-V Redundant Copy Elimination", false, false) 7281ad6265SDimitry Andric 73bdd1243dSDimitry Andric static bool 74bdd1243dSDimitry Andric guaranteesZeroRegInBlock(MachineBasicBlock &MBB, 75bdd1243dSDimitry Andric const SmallVectorImpl<MachineOperand> &Cond, 76bdd1243dSDimitry Andric MachineBasicBlock *TBB) { 77bdd1243dSDimitry Andric assert(Cond.size() == 3 && "Unexpected number of operands"); 78bdd1243dSDimitry Andric assert(TBB != nullptr && "Expected branch target basic block"); 79bdd1243dSDimitry Andric auto CC = static_cast<RISCVCC::CondCode>(Cond[0].getImm()); 80*0fca6ea1SDimitry Andric if (CC == RISCVCC::COND_EQ && Cond[2].isReg() && 81*0fca6ea1SDimitry Andric Cond[2].getReg() == RISCV::X0 && TBB == &MBB) 8281ad6265SDimitry Andric return true; 83*0fca6ea1SDimitry Andric if (CC == RISCVCC::COND_NE && Cond[2].isReg() && 84*0fca6ea1SDimitry Andric Cond[2].getReg() == RISCV::X0 && TBB != &MBB) 8581ad6265SDimitry Andric return true; 8681ad6265SDimitry Andric return false; 8781ad6265SDimitry Andric } 8881ad6265SDimitry Andric 8981ad6265SDimitry Andric bool RISCVRedundantCopyElimination::optimizeBlock(MachineBasicBlock &MBB) { 9081ad6265SDimitry Andric // Check if the current basic block has a single predecessor. 9181ad6265SDimitry Andric if (MBB.pred_size() != 1) 9281ad6265SDimitry Andric return false; 9381ad6265SDimitry Andric 9481ad6265SDimitry Andric // Check if the predecessor has two successors, implying the block ends in a 9581ad6265SDimitry Andric // conditional branch. 9681ad6265SDimitry Andric MachineBasicBlock *PredMBB = *MBB.pred_begin(); 9781ad6265SDimitry Andric if (PredMBB->succ_size() != 2) 9881ad6265SDimitry Andric return false; 9981ad6265SDimitry Andric 100bdd1243dSDimitry Andric MachineBasicBlock *TBB = nullptr, *FBB = nullptr; 101bdd1243dSDimitry Andric SmallVector<MachineOperand, 3> Cond; 102bdd1243dSDimitry Andric if (TII->analyzeBranch(*PredMBB, TBB, FBB, Cond, /*AllowModify*/ false) || 103bdd1243dSDimitry Andric Cond.empty()) 10481ad6265SDimitry Andric return false; 10581ad6265SDimitry Andric 106bdd1243dSDimitry Andric // Is this a branch with X0? 107bdd1243dSDimitry Andric if (!guaranteesZeroRegInBlock(MBB, Cond, TBB)) 10881ad6265SDimitry Andric return false; 10981ad6265SDimitry Andric 110bdd1243dSDimitry Andric Register TargetReg = Cond[1].getReg(); 11181ad6265SDimitry Andric if (!TargetReg) 11281ad6265SDimitry Andric return false; 11381ad6265SDimitry Andric 11481ad6265SDimitry Andric bool Changed = false; 11581ad6265SDimitry Andric MachineBasicBlock::iterator LastChange = MBB.begin(); 11681ad6265SDimitry Andric // Remove redundant Copy instructions unless TargetReg is modified. 11781ad6265SDimitry Andric for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); I != E;) { 11881ad6265SDimitry Andric MachineInstr *MI = &*I; 11981ad6265SDimitry Andric ++I; 12081ad6265SDimitry Andric if (MI->isCopy() && MI->getOperand(0).isReg() && 12181ad6265SDimitry Andric MI->getOperand(1).isReg()) { 12281ad6265SDimitry Andric Register DefReg = MI->getOperand(0).getReg(); 12381ad6265SDimitry Andric Register SrcReg = MI->getOperand(1).getReg(); 12481ad6265SDimitry Andric 12581ad6265SDimitry Andric if (SrcReg == RISCV::X0 && !MRI->isReserved(DefReg) && 12681ad6265SDimitry Andric TargetReg == DefReg) { 12781ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Remove redundant Copy : "); 12881ad6265SDimitry Andric LLVM_DEBUG(MI->print(dbgs())); 12981ad6265SDimitry Andric 13081ad6265SDimitry Andric MI->eraseFromParent(); 13181ad6265SDimitry Andric Changed = true; 13281ad6265SDimitry Andric LastChange = I; 13381ad6265SDimitry Andric ++NumCopiesRemoved; 13481ad6265SDimitry Andric continue; 13581ad6265SDimitry Andric } 13681ad6265SDimitry Andric } 13781ad6265SDimitry Andric 13881ad6265SDimitry Andric if (MI->modifiesRegister(TargetReg, TRI)) 13981ad6265SDimitry Andric break; 14081ad6265SDimitry Andric } 14181ad6265SDimitry Andric 14281ad6265SDimitry Andric if (!Changed) 14381ad6265SDimitry Andric return false; 14481ad6265SDimitry Andric 145bdd1243dSDimitry Andric MachineBasicBlock::iterator CondBr = PredMBB->getFirstTerminator(); 146bdd1243dSDimitry Andric assert((CondBr->getOpcode() == RISCV::BEQ || 147bdd1243dSDimitry Andric CondBr->getOpcode() == RISCV::BNE) && 148bdd1243dSDimitry Andric "Unexpected opcode"); 149bdd1243dSDimitry Andric assert(CondBr->getOperand(0).getReg() == TargetReg && "Unexpected register"); 150bdd1243dSDimitry Andric 15181ad6265SDimitry Andric // Otherwise, we have to fixup the use-def chain, starting with the 15281ad6265SDimitry Andric // BEQ/BNE. Conservatively mark as much as we can live. 15381ad6265SDimitry Andric CondBr->clearRegisterKills(TargetReg, TRI); 15481ad6265SDimitry Andric 15581ad6265SDimitry Andric // Add newly used reg to the block's live-in list if it isn't there already. 15681ad6265SDimitry Andric if (!MBB.isLiveIn(TargetReg)) 15781ad6265SDimitry Andric MBB.addLiveIn(TargetReg); 15881ad6265SDimitry Andric 15981ad6265SDimitry Andric // Clear any kills of TargetReg between CondBr and the last removed COPY. 16081ad6265SDimitry Andric for (MachineInstr &MMI : make_range(MBB.begin(), LastChange)) 16181ad6265SDimitry Andric MMI.clearRegisterKills(TargetReg, TRI); 16281ad6265SDimitry Andric 16381ad6265SDimitry Andric return true; 16481ad6265SDimitry Andric } 16581ad6265SDimitry Andric 16681ad6265SDimitry Andric bool RISCVRedundantCopyElimination::runOnMachineFunction(MachineFunction &MF) { 16781ad6265SDimitry Andric if (skipFunction(MF.getFunction())) 16881ad6265SDimitry Andric return false; 16981ad6265SDimitry Andric 170bdd1243dSDimitry Andric TII = MF.getSubtarget().getInstrInfo(); 17181ad6265SDimitry Andric TRI = MF.getSubtarget().getRegisterInfo(); 17281ad6265SDimitry Andric MRI = &MF.getRegInfo(); 17381ad6265SDimitry Andric 17481ad6265SDimitry Andric bool Changed = false; 17581ad6265SDimitry Andric for (MachineBasicBlock &MBB : MF) 17681ad6265SDimitry Andric Changed |= optimizeBlock(MBB); 17781ad6265SDimitry Andric 17881ad6265SDimitry Andric return Changed; 17981ad6265SDimitry Andric } 18081ad6265SDimitry Andric 18181ad6265SDimitry Andric FunctionPass *llvm::createRISCVRedundantCopyEliminationPass() { 18281ad6265SDimitry Andric return new RISCVRedundantCopyElimination(); 18381ad6265SDimitry Andric } 184