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