xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVRedundantCopyElimination.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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