xref: /freebsd/contrib/llvm-project/llvm/lib/Target/BPF/BPFMIPeephole.cpp (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
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