1 //===-------------- BPFMIPeephole.cpp - MI Peephole Cleanups -------------===// 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 performs peephole optimizations to cleanup ugly code sequences at 10 // MachineInstruction layer. 11 // 12 // Currently, there are two optimizations implemented: 13 // - One pre-RA MachineSSA pass to eliminate type promotion sequences, those 14 // zero extend 32-bit subregisters to 64-bit registers, if the compiler 15 // could prove the subregisters is defined by 32-bit operations in which 16 // case the upper half of the underlying 64-bit registers were zeroed 17 // implicitly. 18 // 19 // - One post-RA PreEmit pass to do final cleanup on some redundant 20 // instructions generated due to bad RA on subregister. 21 //===----------------------------------------------------------------------===// 22 23 #include "BPF.h" 24 #include "BPFInstrInfo.h" 25 #include "BPFTargetMachine.h" 26 #include "llvm/ADT/Statistic.h" 27 #include "llvm/CodeGen/MachineInstrBuilder.h" 28 #include "llvm/CodeGen/MachineRegisterInfo.h" 29 30 using namespace llvm; 31 32 #define DEBUG_TYPE "bpf-mi-zext-elim" 33 34 STATISTIC(ZExtElemNum, "Number of zero extension shifts eliminated"); 35 36 namespace { 37 38 struct BPFMIPeephole : public MachineFunctionPass { 39 40 static char ID; 41 const BPFInstrInfo *TII; 42 MachineFunction *MF; 43 MachineRegisterInfo *MRI; 44 45 BPFMIPeephole() : MachineFunctionPass(ID) { 46 initializeBPFMIPeepholePass(*PassRegistry::getPassRegistry()); 47 } 48 49 private: 50 // Initialize class variables. 51 void initialize(MachineFunction &MFParm); 52 53 bool isMovFrom32Def(MachineInstr *MovMI); 54 bool eliminateZExtSeq(void); 55 56 public: 57 58 // Main entry point for this pass. 59 bool runOnMachineFunction(MachineFunction &MF) override { 60 if (skipFunction(MF.getFunction())) 61 return false; 62 63 initialize(MF); 64 65 return eliminateZExtSeq(); 66 } 67 }; 68 69 // Initialize class variables. 70 void BPFMIPeephole::initialize(MachineFunction &MFParm) { 71 MF = &MFParm; 72 MRI = &MF->getRegInfo(); 73 TII = MF->getSubtarget<BPFSubtarget>().getInstrInfo(); 74 LLVM_DEBUG(dbgs() << "*** BPF MachineSSA peephole pass ***\n\n"); 75 } 76 77 bool BPFMIPeephole::isMovFrom32Def(MachineInstr *MovMI) 78 { 79 MachineInstr *DefInsn = MRI->getVRegDef(MovMI->getOperand(1).getReg()); 80 81 LLVM_DEBUG(dbgs() << " Def of Mov Src:"); 82 LLVM_DEBUG(DefInsn->dump()); 83 84 if (!DefInsn) 85 return false; 86 87 if (DefInsn->isPHI()) { 88 for (unsigned i = 1, e = DefInsn->getNumOperands(); i < e; i += 2) { 89 MachineOperand &opnd = DefInsn->getOperand(i); 90 91 if (!opnd.isReg()) 92 return false; 93 94 MachineInstr *PhiDef = MRI->getVRegDef(opnd.getReg()); 95 // quick check on PHI incoming definitions. 96 if (!PhiDef || PhiDef->isPHI() || PhiDef->getOpcode() == BPF::COPY) 97 return false; 98 } 99 } 100 101 if (DefInsn->getOpcode() == BPF::COPY) { 102 MachineOperand &opnd = DefInsn->getOperand(1); 103 104 if (!opnd.isReg()) 105 return false; 106 107 unsigned Reg = opnd.getReg(); 108 if ((TargetRegisterInfo::isVirtualRegister(Reg) && 109 MRI->getRegClass(Reg) == &BPF::GPRRegClass)) 110 return false; 111 } 112 113 LLVM_DEBUG(dbgs() << " One ZExt elim sequence identified.\n"); 114 115 return true; 116 } 117 118 bool BPFMIPeephole::eliminateZExtSeq(void) { 119 MachineInstr* ToErase = nullptr; 120 bool Eliminated = false; 121 122 for (MachineBasicBlock &MBB : *MF) { 123 for (MachineInstr &MI : MBB) { 124 // If the previous instruction was marked for elimination, remove it now. 125 if (ToErase) { 126 ToErase->eraseFromParent(); 127 ToErase = nullptr; 128 } 129 130 // Eliminate the 32-bit to 64-bit zero extension sequence when possible. 131 // 132 // MOV_32_64 rB, wA 133 // SLL_ri rB, rB, 32 134 // SRL_ri rB, rB, 32 135 if (MI.getOpcode() == BPF::SRL_ri && 136 MI.getOperand(2).getImm() == 32) { 137 unsigned DstReg = MI.getOperand(0).getReg(); 138 unsigned ShfReg = MI.getOperand(1).getReg(); 139 MachineInstr *SllMI = MRI->getVRegDef(ShfReg); 140 141 LLVM_DEBUG(dbgs() << "Starting SRL found:"); 142 LLVM_DEBUG(MI.dump()); 143 144 if (!SllMI || 145 SllMI->isPHI() || 146 SllMI->getOpcode() != BPF::SLL_ri || 147 SllMI->getOperand(2).getImm() != 32) 148 continue; 149 150 LLVM_DEBUG(dbgs() << " SLL found:"); 151 LLVM_DEBUG(SllMI->dump()); 152 153 MachineInstr *MovMI = MRI->getVRegDef(SllMI->getOperand(1).getReg()); 154 if (!MovMI || 155 MovMI->isPHI() || 156 MovMI->getOpcode() != BPF::MOV_32_64) 157 continue; 158 159 LLVM_DEBUG(dbgs() << " Type cast Mov found:"); 160 LLVM_DEBUG(MovMI->dump()); 161 162 unsigned SubReg = MovMI->getOperand(1).getReg(); 163 if (!isMovFrom32Def(MovMI)) { 164 LLVM_DEBUG(dbgs() 165 << " One ZExt elim sequence failed qualifying elim.\n"); 166 continue; 167 } 168 169 BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(BPF::SUBREG_TO_REG), DstReg) 170 .addImm(0).addReg(SubReg).addImm(BPF::sub_32); 171 172 SllMI->eraseFromParent(); 173 MovMI->eraseFromParent(); 174 // MI is the right shift, we can't erase it in it's own iteration. 175 // Mark it to ToErase, and erase in the next iteration. 176 ToErase = &MI; 177 ZExtElemNum++; 178 Eliminated = true; 179 } 180 } 181 } 182 183 return Eliminated; 184 } 185 186 } // end default namespace 187 188 INITIALIZE_PASS(BPFMIPeephole, DEBUG_TYPE, 189 "BPF MachineSSA Peephole Optimization", false, false) 190 191 char BPFMIPeephole::ID = 0; 192 FunctionPass* llvm::createBPFMIPeepholePass() { return new BPFMIPeephole(); } 193 194 STATISTIC(RedundantMovElemNum, "Number of redundant moves eliminated"); 195 196 namespace { 197 198 struct BPFMIPreEmitPeephole : public MachineFunctionPass { 199 200 static char ID; 201 MachineFunction *MF; 202 const TargetRegisterInfo *TRI; 203 204 BPFMIPreEmitPeephole() : MachineFunctionPass(ID) { 205 initializeBPFMIPreEmitPeepholePass(*PassRegistry::getPassRegistry()); 206 } 207 208 private: 209 // Initialize class variables. 210 void initialize(MachineFunction &MFParm); 211 212 bool eliminateRedundantMov(void); 213 214 public: 215 216 // Main entry point for this pass. 217 bool runOnMachineFunction(MachineFunction &MF) override { 218 if (skipFunction(MF.getFunction())) 219 return false; 220 221 initialize(MF); 222 223 return eliminateRedundantMov(); 224 } 225 }; 226 227 // Initialize class variables. 228 void BPFMIPreEmitPeephole::initialize(MachineFunction &MFParm) { 229 MF = &MFParm; 230 TRI = MF->getSubtarget<BPFSubtarget>().getRegisterInfo(); 231 LLVM_DEBUG(dbgs() << "*** BPF PreEmit peephole pass ***\n\n"); 232 } 233 234 bool BPFMIPreEmitPeephole::eliminateRedundantMov(void) { 235 MachineInstr* ToErase = nullptr; 236 bool Eliminated = false; 237 238 for (MachineBasicBlock &MBB : *MF) { 239 for (MachineInstr &MI : MBB) { 240 // If the previous instruction was marked for elimination, remove it now. 241 if (ToErase) { 242 LLVM_DEBUG(dbgs() << " Redundant Mov Eliminated:"); 243 LLVM_DEBUG(ToErase->dump()); 244 ToErase->eraseFromParent(); 245 ToErase = nullptr; 246 } 247 248 // Eliminate identical move: 249 // 250 // MOV rA, rA 251 // 252 // This is particularly possible to happen when sub-register support 253 // enabled. The special type cast insn MOV_32_64 involves different 254 // register class on src (i32) and dst (i64), RA could generate useless 255 // instruction due to this. 256 if (MI.getOpcode() == BPF::MOV_32_64) { 257 unsigned dst = MI.getOperand(0).getReg(); 258 unsigned dst_sub = TRI->getSubReg(dst, BPF::sub_32); 259 unsigned src = MI.getOperand(1).getReg(); 260 261 if (dst_sub != src) 262 continue; 263 264 ToErase = &MI; 265 RedundantMovElemNum++; 266 Eliminated = true; 267 } 268 } 269 } 270 271 return Eliminated; 272 } 273 274 } // end default namespace 275 276 INITIALIZE_PASS(BPFMIPreEmitPeephole, "bpf-mi-pemit-peephole", 277 "BPF PreEmit Peephole Optimization", false, false) 278 279 char BPFMIPreEmitPeephole::ID = 0; 280 FunctionPass* llvm::createBPFMIPreEmitPeepholePass() 281 { 282 return new BPFMIPreEmitPeephole(); 283 } 284