//===-------------- 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, the only optimization in this pass is 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. // //===----------------------------------------------------------------------===// #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-promotion-elim" STATISTIC(CmpPromotionElemNum, "Number of shifts for CMP promotion 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 eliminateCmpPromotionSeq(void); MachineInstr *getInsnDefZExtSubReg(unsigned Reg) const; void updateInsnSeq(MachineBasicBlock &MBB, MachineInstr &MI, unsigned Reg) const; public: // Main entry point for this pass. bool runOnMachineFunction(MachineFunction &MF) override { if (skipFunction(MF.getFunction())) return false; initialize(MF); return eliminateCmpPromotionSeq(); } }; // Initialize class variables. void BPFMIPeephole::initialize(MachineFunction &MFParm) { MF = &MFParm; MRI = &MF->getRegInfo(); TII = MF->getSubtarget().getInstrInfo(); DEBUG(dbgs() << "*** BPF MI peephole pass ***\n\n"); } MachineInstr *BPFMIPeephole::getInsnDefZExtSubReg(unsigned Reg) const { MachineInstr *Insn = MRI->getVRegDef(Reg); if (!Insn || Insn->isPHI() || Insn->getOpcode() != BPF::SRL_ri || Insn->getOperand(2).getImm() != 32) return nullptr; Insn = MRI->getVRegDef(Insn->getOperand(1).getReg()); if (!Insn || Insn->isPHI() || Insn->getOpcode() != BPF::SLL_ri || Insn->getOperand(2).getImm() != 32) return nullptr; Insn = MRI->getVRegDef(Insn->getOperand(1).getReg()); if (!Insn || Insn->isPHI() || Insn->getOpcode() != BPF::MOV_32_64) return nullptr; Insn = MRI->getVRegDef(Insn->getOperand(1).getReg()); if (!Insn || Insn->isPHI()) return nullptr; if (Insn->getOpcode() == BPF::COPY) { MachineOperand &opnd = Insn->getOperand(1); if (!opnd.isReg()) return nullptr; unsigned Reg = opnd.getReg(); if ((TargetRegisterInfo::isVirtualRegister(Reg) && MRI->getRegClass(Reg) == &BPF::GPRRegClass) || (TargetRegisterInfo::isPhysicalRegister(Reg) && BPF::GPRRegClass.contains(Reg))) return nullptr; } return Insn; } void BPFMIPeephole::updateInsnSeq(MachineBasicBlock &MBB, MachineInstr &MI, unsigned Reg) const { MachineInstr *Mov, *Lshift, *Rshift; unsigned SubReg; DebugLoc DL; Rshift = MRI->getVRegDef(Reg); Lshift = MRI->getVRegDef(Rshift->getOperand(1).getReg()); Mov = MRI->getVRegDef(Lshift->getOperand(1).getReg()); SubReg = Mov->getOperand(1).getReg(); DL = MI.getDebugLoc(); BuildMI(MBB, Rshift, DL, TII->get(BPF::SUBREG_TO_REG), Reg) .addImm(0).addReg(SubReg).addImm(BPF::sub_32); Rshift->eraseFromParent(); Lshift->eraseFromParent(); Mov->eraseFromParent(); CmpPromotionElemNum++; } bool BPFMIPeephole::eliminateCmpPromotionSeq(void) { bool Eliminated = false; MachineInstr *Mov; unsigned Reg; for (MachineBasicBlock &MBB : *MF) { for (MachineInstr &MI : MBB) { switch (MI.getOpcode()) { default: break; case BPF::JUGT_rr: case BPF::JUGE_rr: case BPF::JULT_rr: case BPF::JULE_rr: case BPF::JEQ_rr: case BPF::JNE_rr: Reg = MI.getOperand(1).getReg(); Mov = getInsnDefZExtSubReg(Reg); if (!Mov) break; updateInsnSeq(MBB, MI, Reg); Eliminated = true; // Fallthrough case BPF::JUGT_ri: case BPF::JUGE_ri: case BPF::JULT_ri: case BPF::JULE_ri: case BPF::JEQ_ri: case BPF::JNE_ri: Reg = MI.getOperand(0).getReg(); Mov = getInsnDefZExtSubReg(Reg); if (!Mov) break; updateInsnSeq(MBB, MI, Reg); Eliminated = true; break; } } } return Eliminated; } } // end default namespace INITIALIZE_PASS(BPFMIPeephole, DEBUG_TYPE, "BPF MI Peephole Optimization", false, false) char BPFMIPeephole::ID = 0; FunctionPass* llvm::createBPFMIPeepholePass() { return new BPFMIPeephole(); }