|  | //===-------------- BPFMIPeephole.cpp - MI Peephole Cleanups  -------------===// | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // This pass performs peephole optimizations to cleanup ugly code sequences at | 
|  | // MachineInstruction layer. | 
|  | // | 
|  | // Currently, there are two optimizations implemented: | 
|  | //  - One pre-RA MachineSSA pass to eliminate type promotion sequences, those | 
|  | //    zero extend 32-bit subregisters to 64-bit registers, if the compiler | 
|  | //    could prove the subregisters is defined by 32-bit operations in which | 
|  | //    case the upper half of the underlying 64-bit registers were zeroed | 
|  | //    implicitly. | 
|  | // | 
|  | //  - One post-RA PreEmit pass to do final cleanup on some redundant | 
|  | //    instructions generated due to bad RA on subregister. | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "BPF.h" | 
|  | #include "BPFInstrInfo.h" | 
|  | #include "BPFTargetMachine.h" | 
|  | #include "llvm/ADT/Statistic.h" | 
|  | #include "llvm/CodeGen/MachineInstrBuilder.h" | 
|  | #include "llvm/CodeGen/MachineRegisterInfo.h" | 
|  |  | 
|  | using namespace llvm; | 
|  |  | 
|  | #define DEBUG_TYPE "bpf-mi-zext-elim" | 
|  |  | 
|  | STATISTIC(ZExtElemNum, "Number of zero extension shifts eliminated"); | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | struct BPFMIPeephole : public MachineFunctionPass { | 
|  |  | 
|  | static char ID; | 
|  | const BPFInstrInfo *TII; | 
|  | MachineFunction *MF; | 
|  | MachineRegisterInfo *MRI; | 
|  |  | 
|  | BPFMIPeephole() : MachineFunctionPass(ID) { | 
|  | initializeBPFMIPeepholePass(*PassRegistry::getPassRegistry()); | 
|  | } | 
|  |  | 
|  | private: | 
|  | // Initialize class variables. | 
|  | void initialize(MachineFunction &MFParm); | 
|  |  | 
|  | bool isMovFrom32Def(MachineInstr *MovMI); | 
|  | bool eliminateZExtSeq(void); | 
|  |  | 
|  | public: | 
|  |  | 
|  | // Main entry point for this pass. | 
|  | bool runOnMachineFunction(MachineFunction &MF) override { | 
|  | if (skipFunction(MF.getFunction())) | 
|  | return false; | 
|  |  | 
|  | initialize(MF); | 
|  |  | 
|  | return eliminateZExtSeq(); | 
|  | } | 
|  | }; | 
|  |  | 
|  | // Initialize class variables. | 
|  | void BPFMIPeephole::initialize(MachineFunction &MFParm) { | 
|  | MF = &MFParm; | 
|  | MRI = &MF->getRegInfo(); | 
|  | TII = MF->getSubtarget<BPFSubtarget>().getInstrInfo(); | 
|  | LLVM_DEBUG(dbgs() << "*** BPF MachineSSA peephole pass ***\n\n"); | 
|  | } | 
|  |  | 
|  | bool BPFMIPeephole::isMovFrom32Def(MachineInstr *MovMI) | 
|  | { | 
|  | MachineInstr *DefInsn = MRI->getVRegDef(MovMI->getOperand(1).getReg()); | 
|  |  | 
|  | LLVM_DEBUG(dbgs() << "  Def of Mov Src:"); | 
|  | LLVM_DEBUG(DefInsn->dump()); | 
|  |  | 
|  | if (!DefInsn) | 
|  | return false; | 
|  |  | 
|  | if (DefInsn->isPHI()) { | 
|  | for (unsigned i = 1, e = DefInsn->getNumOperands(); i < e; i += 2) { | 
|  | MachineOperand &opnd = DefInsn->getOperand(i); | 
|  |  | 
|  | if (!opnd.isReg()) | 
|  | return false; | 
|  |  | 
|  | MachineInstr *PhiDef = MRI->getVRegDef(opnd.getReg()); | 
|  | // quick check on PHI incoming definitions. | 
|  | if (!PhiDef || PhiDef->isPHI() || PhiDef->getOpcode() == BPF::COPY) | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (DefInsn->getOpcode() == BPF::COPY) { | 
|  | MachineOperand &opnd = DefInsn->getOperand(1); | 
|  |  | 
|  | if (!opnd.isReg()) | 
|  | return false; | 
|  |  | 
|  | unsigned Reg = opnd.getReg(); | 
|  | if ((TargetRegisterInfo::isVirtualRegister(Reg) && | 
|  | MRI->getRegClass(Reg) == &BPF::GPRRegClass)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | LLVM_DEBUG(dbgs() << "  One ZExt elim sequence identified.\n"); | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool BPFMIPeephole::eliminateZExtSeq(void) { | 
|  | MachineInstr* ToErase = nullptr; | 
|  | bool Eliminated = false; | 
|  |  | 
|  | for (MachineBasicBlock &MBB : *MF) { | 
|  | for (MachineInstr &MI : MBB) { | 
|  | // If the previous instruction was marked for elimination, remove it now. | 
|  | if (ToErase) { | 
|  | ToErase->eraseFromParent(); | 
|  | ToErase = nullptr; | 
|  | } | 
|  |  | 
|  | // Eliminate the 32-bit to 64-bit zero extension sequence when possible. | 
|  | // | 
|  | //   MOV_32_64 rB, wA | 
|  | //   SLL_ri    rB, rB, 32 | 
|  | //   SRL_ri    rB, rB, 32 | 
|  | if (MI.getOpcode() == BPF::SRL_ri && | 
|  | MI.getOperand(2).getImm() == 32) { | 
|  | unsigned DstReg = MI.getOperand(0).getReg(); | 
|  | unsigned ShfReg = MI.getOperand(1).getReg(); | 
|  | MachineInstr *SllMI = MRI->getVRegDef(ShfReg); | 
|  |  | 
|  | LLVM_DEBUG(dbgs() << "Starting SRL found:"); | 
|  | LLVM_DEBUG(MI.dump()); | 
|  |  | 
|  | if (!SllMI || | 
|  | SllMI->isPHI() || | 
|  | SllMI->getOpcode() != BPF::SLL_ri || | 
|  | SllMI->getOperand(2).getImm() != 32) | 
|  | continue; | 
|  |  | 
|  | LLVM_DEBUG(dbgs() << "  SLL found:"); | 
|  | LLVM_DEBUG(SllMI->dump()); | 
|  |  | 
|  | MachineInstr *MovMI = MRI->getVRegDef(SllMI->getOperand(1).getReg()); | 
|  | if (!MovMI || | 
|  | MovMI->isPHI() || | 
|  | MovMI->getOpcode() != BPF::MOV_32_64) | 
|  | continue; | 
|  |  | 
|  | LLVM_DEBUG(dbgs() << "  Type cast Mov found:"); | 
|  | LLVM_DEBUG(MovMI->dump()); | 
|  |  | 
|  | unsigned SubReg = MovMI->getOperand(1).getReg(); | 
|  | if (!isMovFrom32Def(MovMI)) { | 
|  | LLVM_DEBUG(dbgs() | 
|  | << "  One ZExt elim sequence failed qualifying elim.\n"); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(BPF::SUBREG_TO_REG), DstReg) | 
|  | .addImm(0).addReg(SubReg).addImm(BPF::sub_32); | 
|  |  | 
|  | SllMI->eraseFromParent(); | 
|  | MovMI->eraseFromParent(); | 
|  | // MI is the right shift, we can't erase it in it's own iteration. | 
|  | // Mark it to ToErase, and erase in the next iteration. | 
|  | ToErase = &MI; | 
|  | ZExtElemNum++; | 
|  | Eliminated = true; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | return Eliminated; | 
|  | } | 
|  |  | 
|  | } // end default namespace | 
|  |  | 
|  | INITIALIZE_PASS(BPFMIPeephole, DEBUG_TYPE, | 
|  | "BPF MachineSSA Peephole Optimization", false, false) | 
|  |  | 
|  | char BPFMIPeephole::ID = 0; | 
|  | FunctionPass* llvm::createBPFMIPeepholePass() { return new BPFMIPeephole(); } | 
|  |  | 
|  | STATISTIC(RedundantMovElemNum, "Number of redundant moves eliminated"); | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | struct BPFMIPreEmitPeephole : public MachineFunctionPass { | 
|  |  | 
|  | static char ID; | 
|  | MachineFunction *MF; | 
|  | const TargetRegisterInfo *TRI; | 
|  |  | 
|  | BPFMIPreEmitPeephole() : MachineFunctionPass(ID) { | 
|  | initializeBPFMIPreEmitPeepholePass(*PassRegistry::getPassRegistry()); | 
|  | } | 
|  |  | 
|  | private: | 
|  | // Initialize class variables. | 
|  | void initialize(MachineFunction &MFParm); | 
|  |  | 
|  | bool eliminateRedundantMov(void); | 
|  |  | 
|  | public: | 
|  |  | 
|  | // Main entry point for this pass. | 
|  | bool runOnMachineFunction(MachineFunction &MF) override { | 
|  | if (skipFunction(MF.getFunction())) | 
|  | return false; | 
|  |  | 
|  | initialize(MF); | 
|  |  | 
|  | return eliminateRedundantMov(); | 
|  | } | 
|  | }; | 
|  |  | 
|  | // Initialize class variables. | 
|  | void BPFMIPreEmitPeephole::initialize(MachineFunction &MFParm) { | 
|  | MF = &MFParm; | 
|  | TRI = MF->getSubtarget<BPFSubtarget>().getRegisterInfo(); | 
|  | LLVM_DEBUG(dbgs() << "*** BPF PreEmit peephole pass ***\n\n"); | 
|  | } | 
|  |  | 
|  | bool BPFMIPreEmitPeephole::eliminateRedundantMov(void) { | 
|  | MachineInstr* ToErase = nullptr; | 
|  | bool Eliminated = false; | 
|  |  | 
|  | for (MachineBasicBlock &MBB : *MF) { | 
|  | for (MachineInstr &MI : MBB) { | 
|  | // If the previous instruction was marked for elimination, remove it now. | 
|  | if (ToErase) { | 
|  | LLVM_DEBUG(dbgs() << "  Redundant Mov Eliminated:"); | 
|  | LLVM_DEBUG(ToErase->dump()); | 
|  | ToErase->eraseFromParent(); | 
|  | ToErase = nullptr; | 
|  | } | 
|  |  | 
|  | // Eliminate identical move: | 
|  | // | 
|  | //   MOV rA, rA | 
|  | // | 
|  | // This is particularly possible to happen when sub-register support | 
|  | // enabled. The special type cast insn MOV_32_64 involves different | 
|  | // register class on src (i32) and dst (i64), RA could generate useless | 
|  | // instruction due to this. | 
|  | if (MI.getOpcode() == BPF::MOV_32_64) { | 
|  | unsigned dst = MI.getOperand(0).getReg(); | 
|  | unsigned dst_sub = TRI->getSubReg(dst, BPF::sub_32); | 
|  | unsigned src = MI.getOperand(1).getReg(); | 
|  |  | 
|  | if (dst_sub != src) | 
|  | continue; | 
|  |  | 
|  | ToErase = &MI; | 
|  | RedundantMovElemNum++; | 
|  | Eliminated = true; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | return Eliminated; | 
|  | } | 
|  |  | 
|  | } // end default namespace | 
|  |  | 
|  | INITIALIZE_PASS(BPFMIPreEmitPeephole, "bpf-mi-pemit-peephole", | 
|  | "BPF PreEmit Peephole Optimization", false, false) | 
|  |  | 
|  | char BPFMIPreEmitPeephole::ID = 0; | 
|  | FunctionPass* llvm::createBPFMIPreEmitPeepholePass() | 
|  | { | 
|  | return new BPFMIPreEmitPeephole(); | 
|  | } |