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;
RISCVRedundantCopyElimination()4781ad6265SDimitry Andric RISCVRedundantCopyElimination() : MachineFunctionPass(ID) {
4881ad6265SDimitry Andric initializeRISCVRedundantCopyEliminationPass(
4981ad6265SDimitry Andric *PassRegistry::getPassRegistry());
5081ad6265SDimitry Andric }
5181ad6265SDimitry Andric
5281ad6265SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override;
getRequiredProperties() const5381ad6265SDimitry Andric MachineFunctionProperties getRequiredProperties() const override {
5481ad6265SDimitry Andric return MachineFunctionProperties().set(
5581ad6265SDimitry Andric MachineFunctionProperties::Property::NoVRegs);
5681ad6265SDimitry Andric }
5781ad6265SDimitry Andric
getPassName() const5881ad6265SDimitry 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
guaranteesZeroRegInBlock(MachineBasicBlock & MBB,const SmallVectorImpl<MachineOperand> & Cond,MachineBasicBlock * TBB)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
optimizeBlock(MachineBasicBlock & MBB)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
runOnMachineFunction(MachineFunction & MF)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
createRISCVRedundantCopyEliminationPass()18181ad6265SDimitry Andric FunctionPass *llvm::createRISCVRedundantCopyEliminationPass() {
18281ad6265SDimitry Andric return new RISCVRedundantCopyElimination();
18381ad6265SDimitry Andric }
184