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