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" 27*81ad6265SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h" 280b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 290b57cec5SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 308bcb0991SDimitry Andric #include "llvm/Support/Debug.h" 315ffd83dbSDimitry Andric #include <set> 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric using namespace llvm; 340b57cec5SDimitry Andric 350b57cec5SDimitry Andric #define DEBUG_TYPE "bpf-mi-zext-elim" 360b57cec5SDimitry Andric 370b57cec5SDimitry Andric STATISTIC(ZExtElemNum, "Number of zero extension shifts eliminated"); 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric namespace { 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric struct BPFMIPeephole : public MachineFunctionPass { 420b57cec5SDimitry Andric 430b57cec5SDimitry Andric static char ID; 440b57cec5SDimitry Andric const BPFInstrInfo *TII; 450b57cec5SDimitry Andric MachineFunction *MF; 460b57cec5SDimitry Andric MachineRegisterInfo *MRI; 470b57cec5SDimitry Andric 480b57cec5SDimitry Andric BPFMIPeephole() : MachineFunctionPass(ID) { 490b57cec5SDimitry Andric initializeBPFMIPeepholePass(*PassRegistry::getPassRegistry()); 500b57cec5SDimitry Andric } 510b57cec5SDimitry Andric 520b57cec5SDimitry Andric private: 530b57cec5SDimitry Andric // Initialize class variables. 540b57cec5SDimitry Andric void initialize(MachineFunction &MFParm); 550b57cec5SDimitry Andric 56480093f4SDimitry Andric bool isCopyFrom32Def(MachineInstr *CopyMI); 57480093f4SDimitry Andric bool isInsnFrom32Def(MachineInstr *DefInsn); 58480093f4SDimitry Andric bool isPhiFrom32Def(MachineInstr *MovMI); 590b57cec5SDimitry Andric bool isMovFrom32Def(MachineInstr *MovMI); 6004eeddc0SDimitry Andric bool eliminateZExtSeq(); 6104eeddc0SDimitry Andric bool eliminateZExt(); 620b57cec5SDimitry Andric 63480093f4SDimitry Andric std::set<MachineInstr *> PhiInsns; 64480093f4SDimitry Andric 650b57cec5SDimitry Andric public: 660b57cec5SDimitry Andric 670b57cec5SDimitry Andric // Main entry point for this pass. 680b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override { 690b57cec5SDimitry Andric if (skipFunction(MF.getFunction())) 700b57cec5SDimitry Andric return false; 710b57cec5SDimitry Andric 720b57cec5SDimitry Andric initialize(MF); 730b57cec5SDimitry Andric 745ffd83dbSDimitry Andric // First try to eliminate (zext, lshift, rshift) and then 755ffd83dbSDimitry Andric // try to eliminate zext. 765ffd83dbSDimitry Andric bool ZExtSeqExist, ZExtExist; 775ffd83dbSDimitry Andric ZExtSeqExist = eliminateZExtSeq(); 785ffd83dbSDimitry Andric ZExtExist = eliminateZExt(); 795ffd83dbSDimitry Andric return ZExtSeqExist || ZExtExist; 800b57cec5SDimitry Andric } 810b57cec5SDimitry Andric }; 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric // Initialize class variables. 840b57cec5SDimitry Andric void BPFMIPeephole::initialize(MachineFunction &MFParm) { 850b57cec5SDimitry Andric MF = &MFParm; 860b57cec5SDimitry Andric MRI = &MF->getRegInfo(); 870b57cec5SDimitry Andric TII = MF->getSubtarget<BPFSubtarget>().getInstrInfo(); 888bcb0991SDimitry Andric LLVM_DEBUG(dbgs() << "*** BPF MachineSSA ZEXT Elim peephole pass ***\n\n"); 890b57cec5SDimitry Andric } 900b57cec5SDimitry Andric 91480093f4SDimitry Andric bool BPFMIPeephole::isCopyFrom32Def(MachineInstr *CopyMI) 92480093f4SDimitry Andric { 93480093f4SDimitry Andric MachineOperand &opnd = CopyMI->getOperand(1); 94480093f4SDimitry Andric 95480093f4SDimitry Andric if (!opnd.isReg()) 96480093f4SDimitry Andric return false; 97480093f4SDimitry Andric 98480093f4SDimitry Andric // Return false if getting value from a 32bit physical register. 99480093f4SDimitry Andric // Most likely, this physical register is aliased to 100480093f4SDimitry Andric // function call return value or current function parameters. 101480093f4SDimitry Andric Register Reg = opnd.getReg(); 102480093f4SDimitry Andric if (!Register::isVirtualRegister(Reg)) 103480093f4SDimitry Andric return false; 104480093f4SDimitry Andric 105480093f4SDimitry Andric if (MRI->getRegClass(Reg) == &BPF::GPRRegClass) 106480093f4SDimitry Andric return false; 107480093f4SDimitry Andric 108480093f4SDimitry Andric MachineInstr *DefInsn = MRI->getVRegDef(Reg); 109480093f4SDimitry Andric if (!isInsnFrom32Def(DefInsn)) 110480093f4SDimitry Andric return false; 111480093f4SDimitry Andric 112480093f4SDimitry Andric return true; 113480093f4SDimitry Andric } 114480093f4SDimitry Andric 115480093f4SDimitry Andric bool BPFMIPeephole::isPhiFrom32Def(MachineInstr *PhiMI) 116480093f4SDimitry Andric { 117480093f4SDimitry Andric for (unsigned i = 1, e = PhiMI->getNumOperands(); i < e; i += 2) { 118480093f4SDimitry Andric MachineOperand &opnd = PhiMI->getOperand(i); 119480093f4SDimitry Andric 120480093f4SDimitry Andric if (!opnd.isReg()) 121480093f4SDimitry Andric return false; 122480093f4SDimitry Andric 123480093f4SDimitry Andric MachineInstr *PhiDef = MRI->getVRegDef(opnd.getReg()); 124480093f4SDimitry Andric if (!PhiDef) 125480093f4SDimitry Andric return false; 126480093f4SDimitry Andric if (PhiDef->isPHI()) { 127*81ad6265SDimitry Andric if (!PhiInsns.insert(PhiDef).second) 128480093f4SDimitry Andric return false; 129480093f4SDimitry Andric if (!isPhiFrom32Def(PhiDef)) 130480093f4SDimitry Andric return false; 131480093f4SDimitry Andric } 132480093f4SDimitry Andric if (PhiDef->getOpcode() == BPF::COPY && !isCopyFrom32Def(PhiDef)) 133480093f4SDimitry Andric return false; 134480093f4SDimitry Andric } 135480093f4SDimitry Andric 136480093f4SDimitry Andric return true; 137480093f4SDimitry Andric } 138480093f4SDimitry Andric 139480093f4SDimitry Andric // The \p DefInsn instruction defines a virtual register. 140480093f4SDimitry Andric bool BPFMIPeephole::isInsnFrom32Def(MachineInstr *DefInsn) 141480093f4SDimitry Andric { 142480093f4SDimitry Andric if (!DefInsn) 143480093f4SDimitry Andric return false; 144480093f4SDimitry Andric 145480093f4SDimitry Andric if (DefInsn->isPHI()) { 146*81ad6265SDimitry Andric if (!PhiInsns.insert(DefInsn).second) 147480093f4SDimitry Andric return false; 148480093f4SDimitry Andric if (!isPhiFrom32Def(DefInsn)) 149480093f4SDimitry Andric return false; 150480093f4SDimitry Andric } else if (DefInsn->getOpcode() == BPF::COPY) { 151480093f4SDimitry Andric if (!isCopyFrom32Def(DefInsn)) 152480093f4SDimitry Andric return false; 153480093f4SDimitry Andric } 154480093f4SDimitry Andric 155480093f4SDimitry Andric return true; 156480093f4SDimitry Andric } 157480093f4SDimitry Andric 1580b57cec5SDimitry Andric bool BPFMIPeephole::isMovFrom32Def(MachineInstr *MovMI) 1590b57cec5SDimitry Andric { 1600b57cec5SDimitry Andric MachineInstr *DefInsn = MRI->getVRegDef(MovMI->getOperand(1).getReg()); 1610b57cec5SDimitry Andric 1620b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " Def of Mov Src:"); 1630b57cec5SDimitry Andric LLVM_DEBUG(DefInsn->dump()); 1640b57cec5SDimitry Andric 165480093f4SDimitry Andric PhiInsns.clear(); 166480093f4SDimitry Andric if (!isInsnFrom32Def(DefInsn)) 1670b57cec5SDimitry Andric return false; 1680b57cec5SDimitry Andric 1690b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " One ZExt elim sequence identified.\n"); 1700b57cec5SDimitry Andric 1710b57cec5SDimitry Andric return true; 1720b57cec5SDimitry Andric } 1730b57cec5SDimitry Andric 17404eeddc0SDimitry Andric bool BPFMIPeephole::eliminateZExtSeq() { 1750b57cec5SDimitry Andric MachineInstr* ToErase = nullptr; 1760b57cec5SDimitry Andric bool Eliminated = false; 1770b57cec5SDimitry Andric 1780b57cec5SDimitry Andric for (MachineBasicBlock &MBB : *MF) { 1790b57cec5SDimitry Andric for (MachineInstr &MI : MBB) { 1800b57cec5SDimitry Andric // If the previous instruction was marked for elimination, remove it now. 1810b57cec5SDimitry Andric if (ToErase) { 1820b57cec5SDimitry Andric ToErase->eraseFromParent(); 1830b57cec5SDimitry Andric ToErase = nullptr; 1840b57cec5SDimitry Andric } 1850b57cec5SDimitry Andric 1860b57cec5SDimitry Andric // Eliminate the 32-bit to 64-bit zero extension sequence when possible. 1870b57cec5SDimitry Andric // 1880b57cec5SDimitry Andric // MOV_32_64 rB, wA 1890b57cec5SDimitry Andric // SLL_ri rB, rB, 32 1900b57cec5SDimitry Andric // SRL_ri rB, rB, 32 1910b57cec5SDimitry Andric if (MI.getOpcode() == BPF::SRL_ri && 1920b57cec5SDimitry Andric MI.getOperand(2).getImm() == 32) { 1938bcb0991SDimitry Andric Register DstReg = MI.getOperand(0).getReg(); 1948bcb0991SDimitry Andric Register ShfReg = MI.getOperand(1).getReg(); 1950b57cec5SDimitry Andric MachineInstr *SllMI = MRI->getVRegDef(ShfReg); 1960b57cec5SDimitry Andric 1970b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Starting SRL found:"); 1980b57cec5SDimitry Andric LLVM_DEBUG(MI.dump()); 1990b57cec5SDimitry Andric 2000b57cec5SDimitry Andric if (!SllMI || 2010b57cec5SDimitry Andric SllMI->isPHI() || 2020b57cec5SDimitry Andric SllMI->getOpcode() != BPF::SLL_ri || 2030b57cec5SDimitry Andric SllMI->getOperand(2).getImm() != 32) 2040b57cec5SDimitry Andric continue; 2050b57cec5SDimitry Andric 2060b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " SLL found:"); 2070b57cec5SDimitry Andric LLVM_DEBUG(SllMI->dump()); 2080b57cec5SDimitry Andric 2090b57cec5SDimitry Andric MachineInstr *MovMI = MRI->getVRegDef(SllMI->getOperand(1).getReg()); 2100b57cec5SDimitry Andric if (!MovMI || 2110b57cec5SDimitry Andric MovMI->isPHI() || 2120b57cec5SDimitry Andric MovMI->getOpcode() != BPF::MOV_32_64) 2130b57cec5SDimitry Andric continue; 2140b57cec5SDimitry Andric 2150b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " Type cast Mov found:"); 2160b57cec5SDimitry Andric LLVM_DEBUG(MovMI->dump()); 2170b57cec5SDimitry Andric 2188bcb0991SDimitry Andric Register SubReg = MovMI->getOperand(1).getReg(); 2190b57cec5SDimitry Andric if (!isMovFrom32Def(MovMI)) { 2200b57cec5SDimitry Andric LLVM_DEBUG(dbgs() 2210b57cec5SDimitry Andric << " One ZExt elim sequence failed qualifying elim.\n"); 2220b57cec5SDimitry Andric continue; 2230b57cec5SDimitry Andric } 2240b57cec5SDimitry Andric 2250b57cec5SDimitry Andric BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(BPF::SUBREG_TO_REG), DstReg) 2260b57cec5SDimitry Andric .addImm(0).addReg(SubReg).addImm(BPF::sub_32); 2270b57cec5SDimitry Andric 2280b57cec5SDimitry Andric SllMI->eraseFromParent(); 2290b57cec5SDimitry Andric MovMI->eraseFromParent(); 2300b57cec5SDimitry Andric // MI is the right shift, we can't erase it in it's own iteration. 2310b57cec5SDimitry Andric // Mark it to ToErase, and erase in the next iteration. 2320b57cec5SDimitry Andric ToErase = &MI; 2330b57cec5SDimitry Andric ZExtElemNum++; 2340b57cec5SDimitry Andric Eliminated = true; 2350b57cec5SDimitry Andric } 2360b57cec5SDimitry Andric } 2370b57cec5SDimitry Andric } 2380b57cec5SDimitry Andric 2390b57cec5SDimitry Andric return Eliminated; 2400b57cec5SDimitry Andric } 2410b57cec5SDimitry Andric 24204eeddc0SDimitry Andric bool BPFMIPeephole::eliminateZExt() { 2435ffd83dbSDimitry Andric MachineInstr* ToErase = nullptr; 2445ffd83dbSDimitry Andric bool Eliminated = false; 2455ffd83dbSDimitry Andric 2465ffd83dbSDimitry Andric for (MachineBasicBlock &MBB : *MF) { 2475ffd83dbSDimitry Andric for (MachineInstr &MI : MBB) { 2485ffd83dbSDimitry Andric // If the previous instruction was marked for elimination, remove it now. 2495ffd83dbSDimitry Andric if (ToErase) { 2505ffd83dbSDimitry Andric ToErase->eraseFromParent(); 2515ffd83dbSDimitry Andric ToErase = nullptr; 2525ffd83dbSDimitry Andric } 2535ffd83dbSDimitry Andric 2545ffd83dbSDimitry Andric if (MI.getOpcode() != BPF::MOV_32_64) 2555ffd83dbSDimitry Andric continue; 2565ffd83dbSDimitry Andric 2575ffd83dbSDimitry Andric // Eliminate MOV_32_64 if possible. 2585ffd83dbSDimitry Andric // MOV_32_64 rA, wB 2595ffd83dbSDimitry Andric // 2605ffd83dbSDimitry Andric // If wB has been zero extended, replace it with a SUBREG_TO_REG. 2615ffd83dbSDimitry Andric // This is to workaround BPF programs where pkt->{data, data_end} 2625ffd83dbSDimitry Andric // is encoded as u32, but actually the verifier populates them 2635ffd83dbSDimitry Andric // as 64bit pointer. The MOV_32_64 will zero out the top 32 bits. 2645ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << "Candidate MOV_32_64 instruction:"); 2655ffd83dbSDimitry Andric LLVM_DEBUG(MI.dump()); 2665ffd83dbSDimitry Andric 2675ffd83dbSDimitry Andric if (!isMovFrom32Def(&MI)) 2685ffd83dbSDimitry Andric continue; 2695ffd83dbSDimitry Andric 2705ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << "Removing the MOV_32_64 instruction\n"); 2715ffd83dbSDimitry Andric 2725ffd83dbSDimitry Andric Register dst = MI.getOperand(0).getReg(); 2735ffd83dbSDimitry Andric Register src = MI.getOperand(1).getReg(); 2745ffd83dbSDimitry Andric 2755ffd83dbSDimitry Andric // Build a SUBREG_TO_REG instruction. 2765ffd83dbSDimitry Andric BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(BPF::SUBREG_TO_REG), dst) 2775ffd83dbSDimitry Andric .addImm(0).addReg(src).addImm(BPF::sub_32); 2785ffd83dbSDimitry Andric 2795ffd83dbSDimitry Andric ToErase = &MI; 2805ffd83dbSDimitry Andric Eliminated = true; 2815ffd83dbSDimitry Andric } 2825ffd83dbSDimitry Andric } 2835ffd83dbSDimitry Andric 2845ffd83dbSDimitry Andric return Eliminated; 2855ffd83dbSDimitry Andric } 2865ffd83dbSDimitry Andric 2870b57cec5SDimitry Andric } // end default namespace 2880b57cec5SDimitry Andric 2890b57cec5SDimitry Andric INITIALIZE_PASS(BPFMIPeephole, DEBUG_TYPE, 2908bcb0991SDimitry Andric "BPF MachineSSA Peephole Optimization For ZEXT Eliminate", 2918bcb0991SDimitry Andric false, false) 2920b57cec5SDimitry Andric 2930b57cec5SDimitry Andric char BPFMIPeephole::ID = 0; 2940b57cec5SDimitry Andric FunctionPass* llvm::createBPFMIPeepholePass() { return new BPFMIPeephole(); } 2950b57cec5SDimitry Andric 2960b57cec5SDimitry Andric STATISTIC(RedundantMovElemNum, "Number of redundant moves eliminated"); 2970b57cec5SDimitry Andric 2980b57cec5SDimitry Andric namespace { 2990b57cec5SDimitry Andric 3000b57cec5SDimitry Andric struct BPFMIPreEmitPeephole : public MachineFunctionPass { 3010b57cec5SDimitry Andric 3020b57cec5SDimitry Andric static char ID; 3030b57cec5SDimitry Andric MachineFunction *MF; 3040b57cec5SDimitry Andric const TargetRegisterInfo *TRI; 3050b57cec5SDimitry Andric 3060b57cec5SDimitry Andric BPFMIPreEmitPeephole() : MachineFunctionPass(ID) { 3070b57cec5SDimitry Andric initializeBPFMIPreEmitPeepholePass(*PassRegistry::getPassRegistry()); 3080b57cec5SDimitry Andric } 3090b57cec5SDimitry Andric 3100b57cec5SDimitry Andric private: 3110b57cec5SDimitry Andric // Initialize class variables. 3120b57cec5SDimitry Andric void initialize(MachineFunction &MFParm); 3130b57cec5SDimitry Andric 31404eeddc0SDimitry Andric bool eliminateRedundantMov(); 3150b57cec5SDimitry Andric 3160b57cec5SDimitry Andric public: 3170b57cec5SDimitry Andric 3180b57cec5SDimitry Andric // Main entry point for this pass. 3190b57cec5SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override { 3200b57cec5SDimitry Andric if (skipFunction(MF.getFunction())) 3210b57cec5SDimitry Andric return false; 3220b57cec5SDimitry Andric 3230b57cec5SDimitry Andric initialize(MF); 3240b57cec5SDimitry Andric 3250b57cec5SDimitry Andric return eliminateRedundantMov(); 3260b57cec5SDimitry Andric } 3270b57cec5SDimitry Andric }; 3280b57cec5SDimitry Andric 3290b57cec5SDimitry Andric // Initialize class variables. 3300b57cec5SDimitry Andric void BPFMIPreEmitPeephole::initialize(MachineFunction &MFParm) { 3310b57cec5SDimitry Andric MF = &MFParm; 3320b57cec5SDimitry Andric TRI = MF->getSubtarget<BPFSubtarget>().getRegisterInfo(); 3330b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "*** BPF PreEmit peephole pass ***\n\n"); 3340b57cec5SDimitry Andric } 3350b57cec5SDimitry Andric 33604eeddc0SDimitry Andric bool BPFMIPreEmitPeephole::eliminateRedundantMov() { 3370b57cec5SDimitry Andric MachineInstr* ToErase = nullptr; 3380b57cec5SDimitry Andric bool Eliminated = false; 3390b57cec5SDimitry Andric 3400b57cec5SDimitry Andric for (MachineBasicBlock &MBB : *MF) { 3410b57cec5SDimitry Andric for (MachineInstr &MI : MBB) { 3420b57cec5SDimitry Andric // If the previous instruction was marked for elimination, remove it now. 3430b57cec5SDimitry Andric if (ToErase) { 3440b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " Redundant Mov Eliminated:"); 3450b57cec5SDimitry Andric LLVM_DEBUG(ToErase->dump()); 3460b57cec5SDimitry Andric ToErase->eraseFromParent(); 3470b57cec5SDimitry Andric ToErase = nullptr; 3480b57cec5SDimitry Andric } 3490b57cec5SDimitry Andric 3500b57cec5SDimitry Andric // Eliminate identical move: 3510b57cec5SDimitry Andric // 3520b57cec5SDimitry Andric // MOV rA, rA 3530b57cec5SDimitry Andric // 3545ffd83dbSDimitry Andric // Note that we cannot remove 3555ffd83dbSDimitry Andric // MOV_32_64 rA, wA 3565ffd83dbSDimitry Andric // MOV_rr_32 wA, wA 3575ffd83dbSDimitry Andric // as these two instructions having side effects, zeroing out 3585ffd83dbSDimitry Andric // top 32 bits of rA. 3598bcb0991SDimitry Andric unsigned Opcode = MI.getOpcode(); 3605ffd83dbSDimitry Andric if (Opcode == BPF::MOV_rr) { 3618bcb0991SDimitry Andric Register dst = MI.getOperand(0).getReg(); 3628bcb0991SDimitry Andric Register src = MI.getOperand(1).getReg(); 3630b57cec5SDimitry Andric 3648bcb0991SDimitry Andric if (dst != src) 3650b57cec5SDimitry Andric continue; 3660b57cec5SDimitry Andric 3670b57cec5SDimitry Andric ToErase = &MI; 3680b57cec5SDimitry Andric RedundantMovElemNum++; 3690b57cec5SDimitry Andric Eliminated = true; 3700b57cec5SDimitry Andric } 3710b57cec5SDimitry Andric } 3720b57cec5SDimitry Andric } 3730b57cec5SDimitry Andric 3740b57cec5SDimitry Andric return Eliminated; 3750b57cec5SDimitry Andric } 3760b57cec5SDimitry Andric 3770b57cec5SDimitry Andric } // end default namespace 3780b57cec5SDimitry Andric 3790b57cec5SDimitry Andric INITIALIZE_PASS(BPFMIPreEmitPeephole, "bpf-mi-pemit-peephole", 3800b57cec5SDimitry Andric "BPF PreEmit Peephole Optimization", false, false) 3810b57cec5SDimitry Andric 3820b57cec5SDimitry Andric char BPFMIPreEmitPeephole::ID = 0; 3830b57cec5SDimitry Andric FunctionPass* llvm::createBPFMIPreEmitPeepholePass() 3840b57cec5SDimitry Andric { 3850b57cec5SDimitry Andric return new BPFMIPreEmitPeephole(); 3860b57cec5SDimitry Andric } 3878bcb0991SDimitry Andric 3888bcb0991SDimitry Andric STATISTIC(TruncElemNum, "Number of truncation eliminated"); 3898bcb0991SDimitry Andric 3908bcb0991SDimitry Andric namespace { 3918bcb0991SDimitry Andric 3928bcb0991SDimitry Andric struct BPFMIPeepholeTruncElim : public MachineFunctionPass { 3938bcb0991SDimitry Andric 3948bcb0991SDimitry Andric static char ID; 3958bcb0991SDimitry Andric const BPFInstrInfo *TII; 3968bcb0991SDimitry Andric MachineFunction *MF; 3978bcb0991SDimitry Andric MachineRegisterInfo *MRI; 3988bcb0991SDimitry Andric 3998bcb0991SDimitry Andric BPFMIPeepholeTruncElim() : MachineFunctionPass(ID) { 4008bcb0991SDimitry Andric initializeBPFMIPeepholeTruncElimPass(*PassRegistry::getPassRegistry()); 4018bcb0991SDimitry Andric } 4028bcb0991SDimitry Andric 4038bcb0991SDimitry Andric private: 4048bcb0991SDimitry Andric // Initialize class variables. 4058bcb0991SDimitry Andric void initialize(MachineFunction &MFParm); 4068bcb0991SDimitry Andric 40704eeddc0SDimitry Andric bool eliminateTruncSeq(); 4088bcb0991SDimitry Andric 4098bcb0991SDimitry Andric public: 4108bcb0991SDimitry Andric 4118bcb0991SDimitry Andric // Main entry point for this pass. 4128bcb0991SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override { 4138bcb0991SDimitry Andric if (skipFunction(MF.getFunction())) 4148bcb0991SDimitry Andric return false; 4158bcb0991SDimitry Andric 4168bcb0991SDimitry Andric initialize(MF); 4178bcb0991SDimitry Andric 4188bcb0991SDimitry Andric return eliminateTruncSeq(); 4198bcb0991SDimitry Andric } 4208bcb0991SDimitry Andric }; 4218bcb0991SDimitry Andric 4228bcb0991SDimitry Andric static bool TruncSizeCompatible(int TruncSize, unsigned opcode) 4238bcb0991SDimitry Andric { 4248bcb0991SDimitry Andric if (TruncSize == 1) 4258bcb0991SDimitry Andric return opcode == BPF::LDB || opcode == BPF::LDB32; 4268bcb0991SDimitry Andric 4278bcb0991SDimitry Andric if (TruncSize == 2) 4288bcb0991SDimitry Andric return opcode == BPF::LDH || opcode == BPF::LDH32; 4298bcb0991SDimitry Andric 4308bcb0991SDimitry Andric if (TruncSize == 4) 4318bcb0991SDimitry Andric return opcode == BPF::LDW || opcode == BPF::LDW32; 4328bcb0991SDimitry Andric 4338bcb0991SDimitry Andric return false; 4348bcb0991SDimitry Andric } 4358bcb0991SDimitry Andric 4368bcb0991SDimitry Andric // Initialize class variables. 4378bcb0991SDimitry Andric void BPFMIPeepholeTruncElim::initialize(MachineFunction &MFParm) { 4388bcb0991SDimitry Andric MF = &MFParm; 4398bcb0991SDimitry Andric MRI = &MF->getRegInfo(); 4408bcb0991SDimitry Andric TII = MF->getSubtarget<BPFSubtarget>().getInstrInfo(); 4418bcb0991SDimitry Andric LLVM_DEBUG(dbgs() << "*** BPF MachineSSA TRUNC Elim peephole pass ***\n\n"); 4428bcb0991SDimitry Andric } 4438bcb0991SDimitry Andric 4448bcb0991SDimitry Andric // Reg truncating is often the result of 8/16/32bit->64bit or 4458bcb0991SDimitry Andric // 8/16bit->32bit conversion. If the reg value is loaded with 4468bcb0991SDimitry Andric // masked byte width, the AND operation can be removed since 4478bcb0991SDimitry Andric // BPF LOAD already has zero extension. 4488bcb0991SDimitry Andric // 4498bcb0991SDimitry Andric // This also solved a correctness issue. 4508bcb0991SDimitry Andric // In BPF socket-related program, e.g., __sk_buff->{data, data_end} 4518bcb0991SDimitry Andric // are 32-bit registers, but later on, kernel verifier will rewrite 4528bcb0991SDimitry Andric // it with 64-bit value. Therefore, truncating the value after the 4538bcb0991SDimitry Andric // load will result in incorrect code. 45404eeddc0SDimitry Andric bool BPFMIPeepholeTruncElim::eliminateTruncSeq() { 4558bcb0991SDimitry Andric MachineInstr* ToErase = nullptr; 4568bcb0991SDimitry Andric bool Eliminated = false; 4578bcb0991SDimitry Andric 4588bcb0991SDimitry Andric for (MachineBasicBlock &MBB : *MF) { 4598bcb0991SDimitry Andric for (MachineInstr &MI : MBB) { 4608bcb0991SDimitry Andric // The second insn to remove if the eliminate candidate is a pair. 4618bcb0991SDimitry Andric MachineInstr *MI2 = nullptr; 4628bcb0991SDimitry Andric Register DstReg, SrcReg; 4638bcb0991SDimitry Andric MachineInstr *DefMI; 4648bcb0991SDimitry Andric int TruncSize = -1; 4658bcb0991SDimitry Andric 4668bcb0991SDimitry Andric // If the previous instruction was marked for elimination, remove it now. 4678bcb0991SDimitry Andric if (ToErase) { 4688bcb0991SDimitry Andric ToErase->eraseFromParent(); 4698bcb0991SDimitry Andric ToErase = nullptr; 4708bcb0991SDimitry Andric } 4718bcb0991SDimitry Andric 4728bcb0991SDimitry Andric // AND A, 0xFFFFFFFF will be turned into SLL/SRL pair due to immediate 4738bcb0991SDimitry Andric // for BPF ANDI is i32, and this case only happens on ALU64. 4748bcb0991SDimitry Andric if (MI.getOpcode() == BPF::SRL_ri && 4758bcb0991SDimitry Andric MI.getOperand(2).getImm() == 32) { 4768bcb0991SDimitry Andric SrcReg = MI.getOperand(1).getReg(); 47723408297SDimitry Andric if (!MRI->hasOneNonDBGUse(SrcReg)) 47823408297SDimitry Andric continue; 47923408297SDimitry Andric 4808bcb0991SDimitry Andric MI2 = MRI->getVRegDef(SrcReg); 4818bcb0991SDimitry Andric DstReg = MI.getOperand(0).getReg(); 4828bcb0991SDimitry Andric 4838bcb0991SDimitry Andric if (!MI2 || 4848bcb0991SDimitry Andric MI2->getOpcode() != BPF::SLL_ri || 4858bcb0991SDimitry Andric MI2->getOperand(2).getImm() != 32) 4868bcb0991SDimitry Andric continue; 4878bcb0991SDimitry Andric 4888bcb0991SDimitry Andric // Update SrcReg. 4898bcb0991SDimitry Andric SrcReg = MI2->getOperand(1).getReg(); 4908bcb0991SDimitry Andric DefMI = MRI->getVRegDef(SrcReg); 4918bcb0991SDimitry Andric if (DefMI) 4928bcb0991SDimitry Andric TruncSize = 4; 4938bcb0991SDimitry Andric } else if (MI.getOpcode() == BPF::AND_ri || 4948bcb0991SDimitry Andric MI.getOpcode() == BPF::AND_ri_32) { 4958bcb0991SDimitry Andric SrcReg = MI.getOperand(1).getReg(); 4968bcb0991SDimitry Andric DstReg = MI.getOperand(0).getReg(); 4978bcb0991SDimitry Andric DefMI = MRI->getVRegDef(SrcReg); 4988bcb0991SDimitry Andric 4998bcb0991SDimitry Andric if (!DefMI) 5008bcb0991SDimitry Andric continue; 5018bcb0991SDimitry Andric 5028bcb0991SDimitry Andric int64_t imm = MI.getOperand(2).getImm(); 5038bcb0991SDimitry Andric if (imm == 0xff) 5048bcb0991SDimitry Andric TruncSize = 1; 5058bcb0991SDimitry Andric else if (imm == 0xffff) 5068bcb0991SDimitry Andric TruncSize = 2; 5078bcb0991SDimitry Andric } 5088bcb0991SDimitry Andric 5098bcb0991SDimitry Andric if (TruncSize == -1) 5108bcb0991SDimitry Andric continue; 5118bcb0991SDimitry Andric 5128bcb0991SDimitry Andric // The definition is PHI node, check all inputs. 5138bcb0991SDimitry Andric if (DefMI->isPHI()) { 5148bcb0991SDimitry Andric bool CheckFail = false; 5158bcb0991SDimitry Andric 5168bcb0991SDimitry Andric for (unsigned i = 1, e = DefMI->getNumOperands(); i < e; i += 2) { 5178bcb0991SDimitry Andric MachineOperand &opnd = DefMI->getOperand(i); 5188bcb0991SDimitry Andric if (!opnd.isReg()) { 5198bcb0991SDimitry Andric CheckFail = true; 5208bcb0991SDimitry Andric break; 5218bcb0991SDimitry Andric } 5228bcb0991SDimitry Andric 5238bcb0991SDimitry Andric MachineInstr *PhiDef = MRI->getVRegDef(opnd.getReg()); 5248bcb0991SDimitry Andric if (!PhiDef || PhiDef->isPHI() || 5258bcb0991SDimitry Andric !TruncSizeCompatible(TruncSize, PhiDef->getOpcode())) { 5268bcb0991SDimitry Andric CheckFail = true; 5278bcb0991SDimitry Andric break; 5288bcb0991SDimitry Andric } 5298bcb0991SDimitry Andric } 5308bcb0991SDimitry Andric 5318bcb0991SDimitry Andric if (CheckFail) 5328bcb0991SDimitry Andric continue; 5338bcb0991SDimitry Andric } else if (!TruncSizeCompatible(TruncSize, DefMI->getOpcode())) { 5348bcb0991SDimitry Andric continue; 5358bcb0991SDimitry Andric } 5368bcb0991SDimitry Andric 5378bcb0991SDimitry Andric BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(BPF::MOV_rr), DstReg) 5388bcb0991SDimitry Andric .addReg(SrcReg); 5398bcb0991SDimitry Andric 5408bcb0991SDimitry Andric if (MI2) 5418bcb0991SDimitry Andric MI2->eraseFromParent(); 5428bcb0991SDimitry Andric 5438bcb0991SDimitry Andric // Mark it to ToErase, and erase in the next iteration. 5448bcb0991SDimitry Andric ToErase = &MI; 5458bcb0991SDimitry Andric TruncElemNum++; 5468bcb0991SDimitry Andric Eliminated = true; 5478bcb0991SDimitry Andric } 5488bcb0991SDimitry Andric } 5498bcb0991SDimitry Andric 5508bcb0991SDimitry Andric return Eliminated; 5518bcb0991SDimitry Andric } 5528bcb0991SDimitry Andric 5538bcb0991SDimitry Andric } // end default namespace 5548bcb0991SDimitry Andric 5558bcb0991SDimitry Andric INITIALIZE_PASS(BPFMIPeepholeTruncElim, "bpf-mi-trunc-elim", 5568bcb0991SDimitry Andric "BPF MachineSSA Peephole Optimization For TRUNC Eliminate", 5578bcb0991SDimitry Andric false, false) 5588bcb0991SDimitry Andric 5598bcb0991SDimitry Andric char BPFMIPeepholeTruncElim::ID = 0; 5608bcb0991SDimitry Andric FunctionPass* llvm::createBPFMIPeepholeTruncElimPass() 5618bcb0991SDimitry Andric { 5628bcb0991SDimitry Andric return new BPFMIPeepholeTruncElim(); 5638bcb0991SDimitry Andric } 564