10b57cec5SDimitry Andric //===-------------- BPFMIPeephole.cpp - MI Peephole Cleanups -------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This pass performs peephole optimizations to cleanup ugly code sequences at 100b57cec5SDimitry Andric // MachineInstruction layer. 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric // Currently, there are two optimizations implemented: 130b57cec5SDimitry Andric // - One pre-RA MachineSSA pass to eliminate type promotion sequences, those 140b57cec5SDimitry Andric // zero extend 32-bit subregisters to 64-bit registers, if the compiler 150b57cec5SDimitry Andric // could prove the subregisters is defined by 32-bit operations in which 160b57cec5SDimitry Andric // case the upper half of the underlying 64-bit registers were zeroed 170b57cec5SDimitry Andric // implicitly. 180b57cec5SDimitry Andric // 190b57cec5SDimitry Andric // - One post-RA PreEmit pass to do final cleanup on some redundant 200b57cec5SDimitry Andric // instructions generated due to bad RA on subregister. 210b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric #include "BPF.h" 240b57cec5SDimitry Andric #include "BPFInstrInfo.h" 250b57cec5SDimitry Andric #include "BPFTargetMachine.h" 260b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h" 270b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 280b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 29*8bcb0991SDimitry Andric #include "llvm/Support/Debug.h" 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric using namespace llvm; 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric #define DEBUG_TYPE "bpf-mi-zext-elim" 340b57cec5SDimitry Andric 350b57cec5SDimitry Andric STATISTIC(ZExtElemNum, "Number of zero extension shifts eliminated"); 360b57cec5SDimitry Andric 370b57cec5SDimitry Andric namespace { 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric struct BPFMIPeephole : public MachineFunctionPass { 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric static char ID; 420b57cec5SDimitry Andric const BPFInstrInfo *TII; 430b57cec5SDimitry Andric MachineFunction *MF; 440b57cec5SDimitry Andric MachineRegisterInfo *MRI; 450b57cec5SDimitry Andric 460b57cec5SDimitry Andric BPFMIPeephole() : MachineFunctionPass(ID) { 470b57cec5SDimitry Andric initializeBPFMIPeepholePass(*PassRegistry::getPassRegistry()); 480b57cec5SDimitry Andric } 490b57cec5SDimitry Andric 500b57cec5SDimitry Andric private: 510b57cec5SDimitry Andric // Initialize class variables. 520b57cec5SDimitry Andric void initialize(MachineFunction &MFParm); 530b57cec5SDimitry Andric 540b57cec5SDimitry Andric bool isMovFrom32Def(MachineInstr *MovMI); 550b57cec5SDimitry Andric bool eliminateZExtSeq(void); 560b57cec5SDimitry Andric 570b57cec5SDimitry Andric public: 580b57cec5SDimitry Andric 590b57cec5SDimitry Andric // Main entry point for this pass. 600b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override { 610b57cec5SDimitry Andric if (skipFunction(MF.getFunction())) 620b57cec5SDimitry Andric return false; 630b57cec5SDimitry Andric 640b57cec5SDimitry Andric initialize(MF); 650b57cec5SDimitry Andric 660b57cec5SDimitry Andric return eliminateZExtSeq(); 670b57cec5SDimitry Andric } 680b57cec5SDimitry Andric }; 690b57cec5SDimitry Andric 700b57cec5SDimitry Andric // Initialize class variables. 710b57cec5SDimitry Andric void BPFMIPeephole::initialize(MachineFunction &MFParm) { 720b57cec5SDimitry Andric MF = &MFParm; 730b57cec5SDimitry Andric MRI = &MF->getRegInfo(); 740b57cec5SDimitry Andric TII = MF->getSubtarget<BPFSubtarget>().getInstrInfo(); 75*8bcb0991SDimitry Andric LLVM_DEBUG(dbgs() << "*** BPF MachineSSA ZEXT Elim peephole pass ***\n\n"); 760b57cec5SDimitry Andric } 770b57cec5SDimitry Andric 780b57cec5SDimitry Andric bool BPFMIPeephole::isMovFrom32Def(MachineInstr *MovMI) 790b57cec5SDimitry Andric { 800b57cec5SDimitry Andric MachineInstr *DefInsn = MRI->getVRegDef(MovMI->getOperand(1).getReg()); 810b57cec5SDimitry Andric 820b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " Def of Mov Src:"); 830b57cec5SDimitry Andric LLVM_DEBUG(DefInsn->dump()); 840b57cec5SDimitry Andric 850b57cec5SDimitry Andric if (!DefInsn) 860b57cec5SDimitry Andric return false; 870b57cec5SDimitry Andric 880b57cec5SDimitry Andric if (DefInsn->isPHI()) { 890b57cec5SDimitry Andric for (unsigned i = 1, e = DefInsn->getNumOperands(); i < e; i += 2) { 900b57cec5SDimitry Andric MachineOperand &opnd = DefInsn->getOperand(i); 910b57cec5SDimitry Andric 920b57cec5SDimitry Andric if (!opnd.isReg()) 930b57cec5SDimitry Andric return false; 940b57cec5SDimitry Andric 950b57cec5SDimitry Andric MachineInstr *PhiDef = MRI->getVRegDef(opnd.getReg()); 960b57cec5SDimitry Andric // quick check on PHI incoming definitions. 970b57cec5SDimitry Andric if (!PhiDef || PhiDef->isPHI() || PhiDef->getOpcode() == BPF::COPY) 980b57cec5SDimitry Andric return false; 990b57cec5SDimitry Andric } 1000b57cec5SDimitry Andric } 1010b57cec5SDimitry Andric 1020b57cec5SDimitry Andric if (DefInsn->getOpcode() == BPF::COPY) { 1030b57cec5SDimitry Andric MachineOperand &opnd = DefInsn->getOperand(1); 1040b57cec5SDimitry Andric 1050b57cec5SDimitry Andric if (!opnd.isReg()) 1060b57cec5SDimitry Andric return false; 1070b57cec5SDimitry Andric 108*8bcb0991SDimitry Andric Register Reg = opnd.getReg(); 109*8bcb0991SDimitry Andric if ((Register::isVirtualRegister(Reg) && 1100b57cec5SDimitry Andric MRI->getRegClass(Reg) == &BPF::GPRRegClass)) 1110b57cec5SDimitry Andric return false; 1120b57cec5SDimitry Andric } 1130b57cec5SDimitry Andric 1140b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " One ZExt elim sequence identified.\n"); 1150b57cec5SDimitry Andric 1160b57cec5SDimitry Andric return true; 1170b57cec5SDimitry Andric } 1180b57cec5SDimitry Andric 1190b57cec5SDimitry Andric bool BPFMIPeephole::eliminateZExtSeq(void) { 1200b57cec5SDimitry Andric MachineInstr* ToErase = nullptr; 1210b57cec5SDimitry Andric bool Eliminated = false; 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric for (MachineBasicBlock &MBB : *MF) { 1240b57cec5SDimitry Andric for (MachineInstr &MI : MBB) { 1250b57cec5SDimitry Andric // If the previous instruction was marked for elimination, remove it now. 1260b57cec5SDimitry Andric if (ToErase) { 1270b57cec5SDimitry Andric ToErase->eraseFromParent(); 1280b57cec5SDimitry Andric ToErase = nullptr; 1290b57cec5SDimitry Andric } 1300b57cec5SDimitry Andric 1310b57cec5SDimitry Andric // Eliminate the 32-bit to 64-bit zero extension sequence when possible. 1320b57cec5SDimitry Andric // 1330b57cec5SDimitry Andric // MOV_32_64 rB, wA 1340b57cec5SDimitry Andric // SLL_ri rB, rB, 32 1350b57cec5SDimitry Andric // SRL_ri rB, rB, 32 1360b57cec5SDimitry Andric if (MI.getOpcode() == BPF::SRL_ri && 1370b57cec5SDimitry Andric MI.getOperand(2).getImm() == 32) { 138*8bcb0991SDimitry Andric Register DstReg = MI.getOperand(0).getReg(); 139*8bcb0991SDimitry Andric Register ShfReg = MI.getOperand(1).getReg(); 1400b57cec5SDimitry Andric MachineInstr *SllMI = MRI->getVRegDef(ShfReg); 1410b57cec5SDimitry Andric 1420b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Starting SRL found:"); 1430b57cec5SDimitry Andric LLVM_DEBUG(MI.dump()); 1440b57cec5SDimitry Andric 1450b57cec5SDimitry Andric if (!SllMI || 1460b57cec5SDimitry Andric SllMI->isPHI() || 1470b57cec5SDimitry Andric SllMI->getOpcode() != BPF::SLL_ri || 1480b57cec5SDimitry Andric SllMI->getOperand(2).getImm() != 32) 1490b57cec5SDimitry Andric continue; 1500b57cec5SDimitry Andric 1510b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " SLL found:"); 1520b57cec5SDimitry Andric LLVM_DEBUG(SllMI->dump()); 1530b57cec5SDimitry Andric 1540b57cec5SDimitry Andric MachineInstr *MovMI = MRI->getVRegDef(SllMI->getOperand(1).getReg()); 1550b57cec5SDimitry Andric if (!MovMI || 1560b57cec5SDimitry Andric MovMI->isPHI() || 1570b57cec5SDimitry Andric MovMI->getOpcode() != BPF::MOV_32_64) 1580b57cec5SDimitry Andric continue; 1590b57cec5SDimitry Andric 1600b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " Type cast Mov found:"); 1610b57cec5SDimitry Andric LLVM_DEBUG(MovMI->dump()); 1620b57cec5SDimitry Andric 163*8bcb0991SDimitry Andric Register SubReg = MovMI->getOperand(1).getReg(); 1640b57cec5SDimitry Andric if (!isMovFrom32Def(MovMI)) { 1650b57cec5SDimitry Andric LLVM_DEBUG(dbgs() 1660b57cec5SDimitry Andric << " One ZExt elim sequence failed qualifying elim.\n"); 1670b57cec5SDimitry Andric continue; 1680b57cec5SDimitry Andric } 1690b57cec5SDimitry Andric 1700b57cec5SDimitry Andric BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(BPF::SUBREG_TO_REG), DstReg) 1710b57cec5SDimitry Andric .addImm(0).addReg(SubReg).addImm(BPF::sub_32); 1720b57cec5SDimitry Andric 1730b57cec5SDimitry Andric SllMI->eraseFromParent(); 1740b57cec5SDimitry Andric MovMI->eraseFromParent(); 1750b57cec5SDimitry Andric // MI is the right shift, we can't erase it in it's own iteration. 1760b57cec5SDimitry Andric // Mark it to ToErase, and erase in the next iteration. 1770b57cec5SDimitry Andric ToErase = &MI; 1780b57cec5SDimitry Andric ZExtElemNum++; 1790b57cec5SDimitry Andric Eliminated = true; 1800b57cec5SDimitry Andric } 1810b57cec5SDimitry Andric } 1820b57cec5SDimitry Andric } 1830b57cec5SDimitry Andric 1840b57cec5SDimitry Andric return Eliminated; 1850b57cec5SDimitry Andric } 1860b57cec5SDimitry Andric 1870b57cec5SDimitry Andric } // end default namespace 1880b57cec5SDimitry Andric 1890b57cec5SDimitry Andric INITIALIZE_PASS(BPFMIPeephole, DEBUG_TYPE, 190*8bcb0991SDimitry Andric "BPF MachineSSA Peephole Optimization For ZEXT Eliminate", 191*8bcb0991SDimitry Andric false, false) 1920b57cec5SDimitry Andric 1930b57cec5SDimitry Andric char BPFMIPeephole::ID = 0; 1940b57cec5SDimitry Andric FunctionPass* llvm::createBPFMIPeepholePass() { return new BPFMIPeephole(); } 1950b57cec5SDimitry Andric 1960b57cec5SDimitry Andric STATISTIC(RedundantMovElemNum, "Number of redundant moves eliminated"); 1970b57cec5SDimitry Andric 1980b57cec5SDimitry Andric namespace { 1990b57cec5SDimitry Andric 2000b57cec5SDimitry Andric struct BPFMIPreEmitPeephole : public MachineFunctionPass { 2010b57cec5SDimitry Andric 2020b57cec5SDimitry Andric static char ID; 2030b57cec5SDimitry Andric MachineFunction *MF; 2040b57cec5SDimitry Andric const TargetRegisterInfo *TRI; 2050b57cec5SDimitry Andric 2060b57cec5SDimitry Andric BPFMIPreEmitPeephole() : MachineFunctionPass(ID) { 2070b57cec5SDimitry Andric initializeBPFMIPreEmitPeepholePass(*PassRegistry::getPassRegistry()); 2080b57cec5SDimitry Andric } 2090b57cec5SDimitry Andric 2100b57cec5SDimitry Andric private: 2110b57cec5SDimitry Andric // Initialize class variables. 2120b57cec5SDimitry Andric void initialize(MachineFunction &MFParm); 2130b57cec5SDimitry Andric 2140b57cec5SDimitry Andric bool eliminateRedundantMov(void); 2150b57cec5SDimitry Andric 2160b57cec5SDimitry Andric public: 2170b57cec5SDimitry Andric 2180b57cec5SDimitry Andric // Main entry point for this pass. 2190b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override { 2200b57cec5SDimitry Andric if (skipFunction(MF.getFunction())) 2210b57cec5SDimitry Andric return false; 2220b57cec5SDimitry Andric 2230b57cec5SDimitry Andric initialize(MF); 2240b57cec5SDimitry Andric 2250b57cec5SDimitry Andric return eliminateRedundantMov(); 2260b57cec5SDimitry Andric } 2270b57cec5SDimitry Andric }; 2280b57cec5SDimitry Andric 2290b57cec5SDimitry Andric // Initialize class variables. 2300b57cec5SDimitry Andric void BPFMIPreEmitPeephole::initialize(MachineFunction &MFParm) { 2310b57cec5SDimitry Andric MF = &MFParm; 2320b57cec5SDimitry Andric TRI = MF->getSubtarget<BPFSubtarget>().getRegisterInfo(); 2330b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "*** BPF PreEmit peephole pass ***\n\n"); 2340b57cec5SDimitry Andric } 2350b57cec5SDimitry Andric 2360b57cec5SDimitry Andric bool BPFMIPreEmitPeephole::eliminateRedundantMov(void) { 2370b57cec5SDimitry Andric MachineInstr* ToErase = nullptr; 2380b57cec5SDimitry Andric bool Eliminated = false; 2390b57cec5SDimitry Andric 2400b57cec5SDimitry Andric for (MachineBasicBlock &MBB : *MF) { 2410b57cec5SDimitry Andric for (MachineInstr &MI : MBB) { 2420b57cec5SDimitry Andric // If the previous instruction was marked for elimination, remove it now. 2430b57cec5SDimitry Andric if (ToErase) { 2440b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " Redundant Mov Eliminated:"); 2450b57cec5SDimitry Andric LLVM_DEBUG(ToErase->dump()); 2460b57cec5SDimitry Andric ToErase->eraseFromParent(); 2470b57cec5SDimitry Andric ToErase = nullptr; 2480b57cec5SDimitry Andric } 2490b57cec5SDimitry Andric 2500b57cec5SDimitry Andric // Eliminate identical move: 2510b57cec5SDimitry Andric // 2520b57cec5SDimitry Andric // MOV rA, rA 2530b57cec5SDimitry Andric // 2540b57cec5SDimitry Andric // This is particularly possible to happen when sub-register support 2550b57cec5SDimitry Andric // enabled. The special type cast insn MOV_32_64 involves different 2560b57cec5SDimitry Andric // register class on src (i32) and dst (i64), RA could generate useless 2570b57cec5SDimitry Andric // instruction due to this. 258*8bcb0991SDimitry Andric unsigned Opcode = MI.getOpcode(); 259*8bcb0991SDimitry Andric if (Opcode == BPF::MOV_32_64 || 260*8bcb0991SDimitry Andric Opcode == BPF::MOV_rr || Opcode == BPF::MOV_rr_32) { 261*8bcb0991SDimitry Andric Register dst = MI.getOperand(0).getReg(); 262*8bcb0991SDimitry Andric Register src = MI.getOperand(1).getReg(); 2630b57cec5SDimitry Andric 264*8bcb0991SDimitry Andric if (Opcode == BPF::MOV_32_64) 265*8bcb0991SDimitry Andric dst = TRI->getSubReg(dst, BPF::sub_32); 266*8bcb0991SDimitry Andric 267*8bcb0991SDimitry Andric if (dst != src) 2680b57cec5SDimitry Andric continue; 2690b57cec5SDimitry Andric 2700b57cec5SDimitry Andric ToErase = &MI; 2710b57cec5SDimitry Andric RedundantMovElemNum++; 2720b57cec5SDimitry Andric Eliminated = true; 2730b57cec5SDimitry Andric } 2740b57cec5SDimitry Andric } 2750b57cec5SDimitry Andric } 2760b57cec5SDimitry Andric 2770b57cec5SDimitry Andric return Eliminated; 2780b57cec5SDimitry Andric } 2790b57cec5SDimitry Andric 2800b57cec5SDimitry Andric } // end default namespace 2810b57cec5SDimitry Andric 2820b57cec5SDimitry Andric INITIALIZE_PASS(BPFMIPreEmitPeephole, "bpf-mi-pemit-peephole", 2830b57cec5SDimitry Andric "BPF PreEmit Peephole Optimization", false, false) 2840b57cec5SDimitry Andric 2850b57cec5SDimitry Andric char BPFMIPreEmitPeephole::ID = 0; 2860b57cec5SDimitry Andric FunctionPass* llvm::createBPFMIPreEmitPeepholePass() 2870b57cec5SDimitry Andric { 2880b57cec5SDimitry Andric return new BPFMIPreEmitPeephole(); 2890b57cec5SDimitry Andric } 290*8bcb0991SDimitry Andric 291*8bcb0991SDimitry Andric STATISTIC(TruncElemNum, "Number of truncation eliminated"); 292*8bcb0991SDimitry Andric 293*8bcb0991SDimitry Andric namespace { 294*8bcb0991SDimitry Andric 295*8bcb0991SDimitry Andric struct BPFMIPeepholeTruncElim : public MachineFunctionPass { 296*8bcb0991SDimitry Andric 297*8bcb0991SDimitry Andric static char ID; 298*8bcb0991SDimitry Andric const BPFInstrInfo *TII; 299*8bcb0991SDimitry Andric MachineFunction *MF; 300*8bcb0991SDimitry Andric MachineRegisterInfo *MRI; 301*8bcb0991SDimitry Andric 302*8bcb0991SDimitry Andric BPFMIPeepholeTruncElim() : MachineFunctionPass(ID) { 303*8bcb0991SDimitry Andric initializeBPFMIPeepholeTruncElimPass(*PassRegistry::getPassRegistry()); 304*8bcb0991SDimitry Andric } 305*8bcb0991SDimitry Andric 306*8bcb0991SDimitry Andric private: 307*8bcb0991SDimitry Andric // Initialize class variables. 308*8bcb0991SDimitry Andric void initialize(MachineFunction &MFParm); 309*8bcb0991SDimitry Andric 310*8bcb0991SDimitry Andric bool eliminateTruncSeq(void); 311*8bcb0991SDimitry Andric 312*8bcb0991SDimitry Andric public: 313*8bcb0991SDimitry Andric 314*8bcb0991SDimitry Andric // Main entry point for this pass. 315*8bcb0991SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override { 316*8bcb0991SDimitry Andric if (skipFunction(MF.getFunction())) 317*8bcb0991SDimitry Andric return false; 318*8bcb0991SDimitry Andric 319*8bcb0991SDimitry Andric initialize(MF); 320*8bcb0991SDimitry Andric 321*8bcb0991SDimitry Andric return eliminateTruncSeq(); 322*8bcb0991SDimitry Andric } 323*8bcb0991SDimitry Andric }; 324*8bcb0991SDimitry Andric 325*8bcb0991SDimitry Andric static bool TruncSizeCompatible(int TruncSize, unsigned opcode) 326*8bcb0991SDimitry Andric { 327*8bcb0991SDimitry Andric if (TruncSize == 1) 328*8bcb0991SDimitry Andric return opcode == BPF::LDB || opcode == BPF::LDB32; 329*8bcb0991SDimitry Andric 330*8bcb0991SDimitry Andric if (TruncSize == 2) 331*8bcb0991SDimitry Andric return opcode == BPF::LDH || opcode == BPF::LDH32; 332*8bcb0991SDimitry Andric 333*8bcb0991SDimitry Andric if (TruncSize == 4) 334*8bcb0991SDimitry Andric return opcode == BPF::LDW || opcode == BPF::LDW32; 335*8bcb0991SDimitry Andric 336*8bcb0991SDimitry Andric return false; 337*8bcb0991SDimitry Andric } 338*8bcb0991SDimitry Andric 339*8bcb0991SDimitry Andric // Initialize class variables. 340*8bcb0991SDimitry Andric void BPFMIPeepholeTruncElim::initialize(MachineFunction &MFParm) { 341*8bcb0991SDimitry Andric MF = &MFParm; 342*8bcb0991SDimitry Andric MRI = &MF->getRegInfo(); 343*8bcb0991SDimitry Andric TII = MF->getSubtarget<BPFSubtarget>().getInstrInfo(); 344*8bcb0991SDimitry Andric LLVM_DEBUG(dbgs() << "*** BPF MachineSSA TRUNC Elim peephole pass ***\n\n"); 345*8bcb0991SDimitry Andric } 346*8bcb0991SDimitry Andric 347*8bcb0991SDimitry Andric // Reg truncating is often the result of 8/16/32bit->64bit or 348*8bcb0991SDimitry Andric // 8/16bit->32bit conversion. If the reg value is loaded with 349*8bcb0991SDimitry Andric // masked byte width, the AND operation can be removed since 350*8bcb0991SDimitry Andric // BPF LOAD already has zero extension. 351*8bcb0991SDimitry Andric // 352*8bcb0991SDimitry Andric // This also solved a correctness issue. 353*8bcb0991SDimitry Andric // In BPF socket-related program, e.g., __sk_buff->{data, data_end} 354*8bcb0991SDimitry Andric // are 32-bit registers, but later on, kernel verifier will rewrite 355*8bcb0991SDimitry Andric // it with 64-bit value. Therefore, truncating the value after the 356*8bcb0991SDimitry Andric // load will result in incorrect code. 357*8bcb0991SDimitry Andric bool BPFMIPeepholeTruncElim::eliminateTruncSeq(void) { 358*8bcb0991SDimitry Andric MachineInstr* ToErase = nullptr; 359*8bcb0991SDimitry Andric bool Eliminated = false; 360*8bcb0991SDimitry Andric 361*8bcb0991SDimitry Andric for (MachineBasicBlock &MBB : *MF) { 362*8bcb0991SDimitry Andric for (MachineInstr &MI : MBB) { 363*8bcb0991SDimitry Andric // The second insn to remove if the eliminate candidate is a pair. 364*8bcb0991SDimitry Andric MachineInstr *MI2 = nullptr; 365*8bcb0991SDimitry Andric Register DstReg, SrcReg; 366*8bcb0991SDimitry Andric MachineInstr *DefMI; 367*8bcb0991SDimitry Andric int TruncSize = -1; 368*8bcb0991SDimitry Andric 369*8bcb0991SDimitry Andric // If the previous instruction was marked for elimination, remove it now. 370*8bcb0991SDimitry Andric if (ToErase) { 371*8bcb0991SDimitry Andric ToErase->eraseFromParent(); 372*8bcb0991SDimitry Andric ToErase = nullptr; 373*8bcb0991SDimitry Andric } 374*8bcb0991SDimitry Andric 375*8bcb0991SDimitry Andric // AND A, 0xFFFFFFFF will be turned into SLL/SRL pair due to immediate 376*8bcb0991SDimitry Andric // for BPF ANDI is i32, and this case only happens on ALU64. 377*8bcb0991SDimitry Andric if (MI.getOpcode() == BPF::SRL_ri && 378*8bcb0991SDimitry Andric MI.getOperand(2).getImm() == 32) { 379*8bcb0991SDimitry Andric SrcReg = MI.getOperand(1).getReg(); 380*8bcb0991SDimitry Andric MI2 = MRI->getVRegDef(SrcReg); 381*8bcb0991SDimitry Andric DstReg = MI.getOperand(0).getReg(); 382*8bcb0991SDimitry Andric 383*8bcb0991SDimitry Andric if (!MI2 || 384*8bcb0991SDimitry Andric MI2->getOpcode() != BPF::SLL_ri || 385*8bcb0991SDimitry Andric MI2->getOperand(2).getImm() != 32) 386*8bcb0991SDimitry Andric continue; 387*8bcb0991SDimitry Andric 388*8bcb0991SDimitry Andric // Update SrcReg. 389*8bcb0991SDimitry Andric SrcReg = MI2->getOperand(1).getReg(); 390*8bcb0991SDimitry Andric DefMI = MRI->getVRegDef(SrcReg); 391*8bcb0991SDimitry Andric if (DefMI) 392*8bcb0991SDimitry Andric TruncSize = 4; 393*8bcb0991SDimitry Andric } else if (MI.getOpcode() == BPF::AND_ri || 394*8bcb0991SDimitry Andric MI.getOpcode() == BPF::AND_ri_32) { 395*8bcb0991SDimitry Andric SrcReg = MI.getOperand(1).getReg(); 396*8bcb0991SDimitry Andric DstReg = MI.getOperand(0).getReg(); 397*8bcb0991SDimitry Andric DefMI = MRI->getVRegDef(SrcReg); 398*8bcb0991SDimitry Andric 399*8bcb0991SDimitry Andric if (!DefMI) 400*8bcb0991SDimitry Andric continue; 401*8bcb0991SDimitry Andric 402*8bcb0991SDimitry Andric int64_t imm = MI.getOperand(2).getImm(); 403*8bcb0991SDimitry Andric if (imm == 0xff) 404*8bcb0991SDimitry Andric TruncSize = 1; 405*8bcb0991SDimitry Andric else if (imm == 0xffff) 406*8bcb0991SDimitry Andric TruncSize = 2; 407*8bcb0991SDimitry Andric } 408*8bcb0991SDimitry Andric 409*8bcb0991SDimitry Andric if (TruncSize == -1) 410*8bcb0991SDimitry Andric continue; 411*8bcb0991SDimitry Andric 412*8bcb0991SDimitry Andric // The definition is PHI node, check all inputs. 413*8bcb0991SDimitry Andric if (DefMI->isPHI()) { 414*8bcb0991SDimitry Andric bool CheckFail = false; 415*8bcb0991SDimitry Andric 416*8bcb0991SDimitry Andric for (unsigned i = 1, e = DefMI->getNumOperands(); i < e; i += 2) { 417*8bcb0991SDimitry Andric MachineOperand &opnd = DefMI->getOperand(i); 418*8bcb0991SDimitry Andric if (!opnd.isReg()) { 419*8bcb0991SDimitry Andric CheckFail = true; 420*8bcb0991SDimitry Andric break; 421*8bcb0991SDimitry Andric } 422*8bcb0991SDimitry Andric 423*8bcb0991SDimitry Andric MachineInstr *PhiDef = MRI->getVRegDef(opnd.getReg()); 424*8bcb0991SDimitry Andric if (!PhiDef || PhiDef->isPHI() || 425*8bcb0991SDimitry Andric !TruncSizeCompatible(TruncSize, PhiDef->getOpcode())) { 426*8bcb0991SDimitry Andric CheckFail = true; 427*8bcb0991SDimitry Andric break; 428*8bcb0991SDimitry Andric } 429*8bcb0991SDimitry Andric } 430*8bcb0991SDimitry Andric 431*8bcb0991SDimitry Andric if (CheckFail) 432*8bcb0991SDimitry Andric continue; 433*8bcb0991SDimitry Andric } else if (!TruncSizeCompatible(TruncSize, DefMI->getOpcode())) { 434*8bcb0991SDimitry Andric continue; 435*8bcb0991SDimitry Andric } 436*8bcb0991SDimitry Andric 437*8bcb0991SDimitry Andric BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(BPF::MOV_rr), DstReg) 438*8bcb0991SDimitry Andric .addReg(SrcReg); 439*8bcb0991SDimitry Andric 440*8bcb0991SDimitry Andric if (MI2) 441*8bcb0991SDimitry Andric MI2->eraseFromParent(); 442*8bcb0991SDimitry Andric 443*8bcb0991SDimitry Andric // Mark it to ToErase, and erase in the next iteration. 444*8bcb0991SDimitry Andric ToErase = &MI; 445*8bcb0991SDimitry Andric TruncElemNum++; 446*8bcb0991SDimitry Andric Eliminated = true; 447*8bcb0991SDimitry Andric } 448*8bcb0991SDimitry Andric } 449*8bcb0991SDimitry Andric 450*8bcb0991SDimitry Andric return Eliminated; 451*8bcb0991SDimitry Andric } 452*8bcb0991SDimitry Andric 453*8bcb0991SDimitry Andric } // end default namespace 454*8bcb0991SDimitry Andric 455*8bcb0991SDimitry Andric INITIALIZE_PASS(BPFMIPeepholeTruncElim, "bpf-mi-trunc-elim", 456*8bcb0991SDimitry Andric "BPF MachineSSA Peephole Optimization For TRUNC Eliminate", 457*8bcb0991SDimitry Andric false, false) 458*8bcb0991SDimitry Andric 459*8bcb0991SDimitry Andric char BPFMIPeepholeTruncElim::ID = 0; 460*8bcb0991SDimitry Andric FunctionPass* llvm::createBPFMIPeepholeTruncElimPass() 461*8bcb0991SDimitry Andric { 462*8bcb0991SDimitry Andric return new BPFMIPeepholeTruncElim(); 463*8bcb0991SDimitry Andric } 464