1 //=- AArch64RedundantCopyElimination.cpp - Remove useless copy for AArch64 -=//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 // This pass removes unnecessary zero copies in BBs that are targets of
9 // cbz/cbnz instructions. For instance, the copy instruction in the code below
10 // can be removed because the CBZW jumps to BB#2 when W0 is zero.
11 //  BB#1:
12 //    CBZW %W0, <BB#2>
13 //  BB#2:
14 //    %W0 = COPY %WZR
15 // This pass should be run after register allocation.
16 //
17 // FIXME: This should be extended to handle any constant other than zero. E.g.,
18 //   cmp w0, #1
19 //     b.eq .BB1
20 //   BB1:
21 //     mov w0, #1
22 //
23 // FIXME: This could also be extended to check the whole dominance subtree below
24 // the comparison if the compile time regression is acceptable.
25 //
26 //===----------------------------------------------------------------------===//
27 
28 #include "AArch64.h"
29 #include "llvm/ADT/SetVector.h"
30 #include "llvm/ADT/Statistic.h"
31 #include "llvm/ADT/iterator_range.h"
32 #include "llvm/CodeGen/MachineFunctionPass.h"
33 #include "llvm/CodeGen/MachineRegisterInfo.h"
34 #include "llvm/Support/Debug.h"
35 
36 using namespace llvm;
37 
38 #define DEBUG_TYPE "aarch64-copyelim"
39 
40 STATISTIC(NumCopiesRemoved, "Number of copies removed.");
41 
42 namespace {
43 class AArch64RedundantCopyElimination : public MachineFunctionPass {
44   const MachineRegisterInfo *MRI;
45   const TargetRegisterInfo *TRI;
46   BitVector ClobberedRegs;
47 
48 public:
49   static char ID;
50   AArch64RedundantCopyElimination() : MachineFunctionPass(ID) {
51     initializeAArch64RedundantCopyEliminationPass(
52         *PassRegistry::getPassRegistry());
53   }
54   bool optimizeCopy(MachineBasicBlock *MBB);
55   bool runOnMachineFunction(MachineFunction &MF) override;
56   MachineFunctionProperties getRequiredProperties() const override {
57     return MachineFunctionProperties().set(
58         MachineFunctionProperties::Property::NoVRegs);
59   }
60   StringRef getPassName() const override {
61     return "AArch64 Redundant Copy Elimination";
62   }
63 };
64 char AArch64RedundantCopyElimination::ID = 0;
65 }
66 
67 INITIALIZE_PASS(AArch64RedundantCopyElimination, "aarch64-copyelim",
68                 "AArch64 redundant copy elimination pass", false, false)
69 
70 static bool guaranteesZeroRegInBlock(MachineInstr &MI, MachineBasicBlock *MBB) {
71   unsigned Opc = MI.getOpcode();
72   // Check if the current basic block is the target block to which the
73   // CBZ/CBNZ instruction jumps when its Wt/Xt is zero.
74   return ((Opc == AArch64::CBZW || Opc == AArch64::CBZX) &&
75           MBB == MI.getOperand(1).getMBB()) ||
76          ((Opc == AArch64::CBNZW || Opc == AArch64::CBNZX) &&
77           MBB != MI.getOperand(1).getMBB());
78 }
79 
80 /// Remember what registers the specified instruction modifies.
81 static void trackRegDefs(const MachineInstr &MI, BitVector &ClobberedRegs,
82                          const TargetRegisterInfo *TRI) {
83   for (const MachineOperand &MO : MI.operands()) {
84     if (MO.isRegMask()) {
85       ClobberedRegs.setBitsNotInMask(MO.getRegMask());
86       continue;
87     }
88 
89     if (!MO.isReg())
90       continue;
91     unsigned Reg = MO.getReg();
92     if (!Reg)
93       continue;
94     if (!MO.isDef())
95       continue;
96 
97     for (MCRegAliasIterator AI(Reg, TRI, true); AI.isValid(); ++AI)
98       ClobberedRegs.set(*AI);
99   }
100 }
101 
102 bool AArch64RedundantCopyElimination::optimizeCopy(MachineBasicBlock *MBB) {
103   // Check if the current basic block has a single predecessor.
104   if (MBB->pred_size() != 1)
105     return false;
106 
107   // Check if the predecessor has two successors, implying the block ends in a
108   // conditional branch.
109   MachineBasicBlock *PredMBB = *MBB->pred_begin();
110   if (PredMBB->succ_size() != 2)
111     return false;
112 
113   MachineBasicBlock::iterator CompBr = PredMBB->getLastNonDebugInstr();
114   if (CompBr == PredMBB->end())
115     return false;
116 
117   // Keep track of the earliest point in the PredMBB block where kill markers
118   // need to be removed if a COPY is removed.
119   MachineBasicBlock::iterator FirstUse;
120   // Registers that are known to contain zeros at the start of MBB.
121   SmallVector<MCPhysReg, 4> KnownZeroRegs;
122   // Registers clobbered in PredMBB between CompBr instruction and current
123   // instruction being checked in loop.
124   ClobberedRegs.reset();
125   ++CompBr;
126   do {
127     --CompBr;
128     if (!guaranteesZeroRegInBlock(*CompBr, MBB))
129       continue;
130 
131     KnownZeroRegs.push_back(CompBr->getOperand(0).getReg());
132     FirstUse = CompBr;
133     // Look backward in PredMBB for COPYs from the known zero reg to
134     // find other registers that are known to be zero.
135     for (auto PredI = CompBr;; --PredI) {
136       if (PredI->isCopy()) {
137         MCPhysReg CopyDstReg = PredI->getOperand(0).getReg();
138         MCPhysReg CopySrcReg = PredI->getOperand(1).getReg();
139         for (MCPhysReg KnownZeroReg : KnownZeroRegs) {
140           if (ClobberedRegs[KnownZeroReg])
141             continue;
142           // If we have X = COPY Y, and Y is known to be zero, then now X is
143           // known to be zero.
144           if (CopySrcReg == KnownZeroReg && !ClobberedRegs[CopyDstReg]) {
145             KnownZeroRegs.push_back(CopyDstReg);
146             FirstUse = PredI;
147             break;
148           }
149           // If we have X = COPY Y, and X is known to be zero, then now Y is
150           // known to be zero.
151           if (CopyDstReg == KnownZeroReg && !ClobberedRegs[CopySrcReg]) {
152             KnownZeroRegs.push_back(CopySrcReg);
153             FirstUse = PredI;
154             break;
155           }
156         }
157       }
158 
159       // Stop if we get to the beginning of PredMBB.
160       if (PredI == PredMBB->begin())
161         break;
162 
163       trackRegDefs(*PredI, ClobberedRegs, TRI);
164       // Stop if all of the known-zero regs have been clobbered.
165       if (all_of(KnownZeroRegs, [&](MCPhysReg KnownZeroReg) {
166             return ClobberedRegs[KnownZeroReg];
167           }))
168         break;
169     }
170     break;
171 
172   } while (CompBr != PredMBB->begin() && CompBr->isTerminator());
173 
174   // We've not found a known zero register, time to bail out.
175   if (KnownZeroRegs.empty())
176     return false;
177 
178   bool Changed = false;
179   // UsedKnownZeroRegs is the set of KnownZeroRegs that have had uses added to MBB.
180   SmallSetVector<unsigned, 4> UsedKnownZeroRegs;
181   MachineBasicBlock::iterator LastChange = MBB->begin();
182   // Remove redundant Copy instructions unless KnownZeroReg is modified.
183   for (MachineBasicBlock::iterator I = MBB->begin(), E = MBB->end(); I != E;) {
184     MachineInstr *MI = &*I;
185     ++I;
186     bool RemovedCopy = false;
187     if (MI->isCopy()) {
188       MCPhysReg DefReg = MI->getOperand(0).getReg();
189       MCPhysReg SrcReg = MI->getOperand(1).getReg();
190 
191       if ((SrcReg == AArch64::XZR || SrcReg == AArch64::WZR) &&
192           !MRI->isReserved(DefReg)) {
193         for (MCPhysReg KnownZeroReg : KnownZeroRegs) {
194           if (KnownZeroReg == DefReg ||
195               TRI->isSuperRegister(DefReg, KnownZeroReg)) {
196             DEBUG(dbgs() << "Remove redundant Copy : " << *MI);
197 
198             MI->eraseFromParent();
199             Changed = true;
200             LastChange = I;
201             NumCopiesRemoved++;
202             UsedKnownZeroRegs.insert(KnownZeroReg);
203             RemovedCopy = true;
204             break;
205           }
206         }
207       }
208     }
209 
210     // Skip to the next instruction if we removed the COPY from WZR/XZR.
211     if (RemovedCopy)
212       continue;
213 
214     // Remove any regs the MI clobbers from the KnownZeroRegs set.
215     for (unsigned RI = 0; RI < KnownZeroRegs.size();)
216       if (MI->modifiesRegister(KnownZeroRegs[RI], TRI)) {
217         std::swap(KnownZeroRegs[RI], KnownZeroRegs[KnownZeroRegs.size() - 1]);
218         KnownZeroRegs.pop_back();
219         // Don't increment RI since we need to now check the swapped-in
220         // KnownZeroRegs[RI].
221       } else {
222         ++RI;
223       }
224 
225     // Continue until the KnownZeroRegs set is empty.
226     if (KnownZeroRegs.empty())
227       break;
228   }
229 
230   if (!Changed)
231     return false;
232 
233   // Add newly used regs to the block's live-in list if they aren't there
234   // already.
235   for (MCPhysReg KnownZeroReg : UsedKnownZeroRegs)
236     if (!MBB->isLiveIn(KnownZeroReg))
237       MBB->addLiveIn(KnownZeroReg);
238 
239   // Clear kills in the range where changes were made.  This is conservative,
240   // but should be okay since kill markers are being phased out.
241   for (MachineInstr &MMI : make_range(FirstUse, PredMBB->end()))
242     MMI.clearKillInfo();
243   for (MachineInstr &MMI : make_range(MBB->begin(), LastChange))
244     MMI.clearKillInfo();
245 
246   return true;
247 }
248 
249 bool AArch64RedundantCopyElimination::runOnMachineFunction(
250     MachineFunction &MF) {
251   if (skipFunction(*MF.getFunction()))
252     return false;
253   TRI = MF.getSubtarget().getRegisterInfo();
254   MRI = &MF.getRegInfo();
255   ClobberedRegs.resize(TRI->getNumRegs());
256   bool Changed = false;
257   for (MachineBasicBlock &MBB : MF)
258     Changed |= optimizeCopy(&MBB);
259   return Changed;
260 }
261 
262 FunctionPass *llvm::createAArch64RedundantCopyEliminationPass() {
263   return new AArch64RedundantCopyElimination();
264 }
265