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