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].getReg() == RISCV::X0 && TBB == &MBB) |
81 | return true; |
82 | if (CC == RISCVCC::COND_NE && Cond[2].getReg() == RISCV::X0 && TBB != &MBB) |
83 | return true; |
84 | return false; |
85 | } |
86 | |
87 | bool RISCVRedundantCopyElimination::optimizeBlock(MachineBasicBlock &MBB) { |
88 | // Check if the current basic block has a single predecessor. |
89 | if (MBB.pred_size() != 1) |
90 | return false; |
91 | |
92 | // Check if the predecessor has two successors, implying the block ends in a |
93 | // conditional branch. |
94 | MachineBasicBlock *PredMBB = *MBB.pred_begin(); |
95 | if (PredMBB->succ_size() != 2) |
96 | return false; |
97 | |
98 | MachineBasicBlock *TBB = nullptr, *FBB = nullptr; |
99 | SmallVector<MachineOperand, 3> Cond; |
100 | if (TII->analyzeBranch(MBB&: *PredMBB, TBB, FBB, Cond, /*AllowModify*/ false) || |
101 | Cond.empty()) |
102 | return false; |
103 | |
104 | // Is this a branch with X0? |
105 | if (!guaranteesZeroRegInBlock(MBB, Cond, TBB)) |
106 | return false; |
107 | |
108 | Register TargetReg = Cond[1].getReg(); |
109 | if (!TargetReg) |
110 | return false; |
111 | |
112 | bool Changed = false; |
113 | MachineBasicBlock::iterator LastChange = MBB.begin(); |
114 | // Remove redundant Copy instructions unless TargetReg is modified. |
115 | for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); I != E;) { |
116 | MachineInstr *MI = &*I; |
117 | ++I; |
118 | if (MI->isCopy() && MI->getOperand(i: 0).isReg() && |
119 | MI->getOperand(i: 1).isReg()) { |
120 | Register DefReg = MI->getOperand(i: 0).getReg(); |
121 | Register SrcReg = MI->getOperand(i: 1).getReg(); |
122 | |
123 | if (SrcReg == RISCV::X0 && !MRI->isReserved(PhysReg: DefReg) && |
124 | TargetReg == DefReg) { |
125 | LLVM_DEBUG(dbgs() << "Remove redundant Copy : " ); |
126 | LLVM_DEBUG(MI->print(dbgs())); |
127 | |
128 | MI->eraseFromParent(); |
129 | Changed = true; |
130 | LastChange = I; |
131 | ++NumCopiesRemoved; |
132 | continue; |
133 | } |
134 | } |
135 | |
136 | if (MI->modifiesRegister(Reg: TargetReg, TRI)) |
137 | break; |
138 | } |
139 | |
140 | if (!Changed) |
141 | return false; |
142 | |
143 | MachineBasicBlock::iterator CondBr = PredMBB->getFirstTerminator(); |
144 | assert((CondBr->getOpcode() == RISCV::BEQ || |
145 | CondBr->getOpcode() == RISCV::BNE) && |
146 | "Unexpected opcode" ); |
147 | assert(CondBr->getOperand(0).getReg() == TargetReg && "Unexpected register" ); |
148 | |
149 | // Otherwise, we have to fixup the use-def chain, starting with the |
150 | // BEQ/BNE. Conservatively mark as much as we can live. |
151 | CondBr->clearRegisterKills(Reg: TargetReg, RegInfo: TRI); |
152 | |
153 | // Add newly used reg to the block's live-in list if it isn't there already. |
154 | if (!MBB.isLiveIn(Reg: TargetReg)) |
155 | MBB.addLiveIn(PhysReg: TargetReg); |
156 | |
157 | // Clear any kills of TargetReg between CondBr and the last removed COPY. |
158 | for (MachineInstr &MMI : make_range(x: MBB.begin(), y: LastChange)) |
159 | MMI.clearRegisterKills(Reg: TargetReg, RegInfo: TRI); |
160 | |
161 | return true; |
162 | } |
163 | |
164 | bool RISCVRedundantCopyElimination::runOnMachineFunction(MachineFunction &MF) { |
165 | if (skipFunction(F: MF.getFunction())) |
166 | return false; |
167 | |
168 | TII = MF.getSubtarget().getInstrInfo(); |
169 | TRI = MF.getSubtarget().getRegisterInfo(); |
170 | MRI = &MF.getRegInfo(); |
171 | |
172 | bool Changed = false; |
173 | for (MachineBasicBlock &MBB : MF) |
174 | Changed |= optimizeBlock(MBB); |
175 | |
176 | return Changed; |
177 | } |
178 | |
179 | FunctionPass *llvm::createRISCVRedundantCopyEliminationPass() { |
180 | return new RISCVRedundantCopyElimination(); |
181 | } |
182 | |