1 //===-------------- BPFMIPeephole.cpp - MI Peephole Cleanups  -------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This pass performs peephole optimizations to cleanup ugly code sequences at
11 // MachineInstruction layer.
12 //
13 // Currently, the only optimization in this pass is to eliminate type promotion
14 // sequences, those zero extend 32-bit subregisters to 64-bit registers, if the
15 // compiler could prove the subregisters is defined by 32-bit operations in
16 // which case the upper half of the underlying 64-bit registers were zeroed
17 // implicitly.
18 //
19 //===----------------------------------------------------------------------===//
20 
21 #include "BPF.h"
22 #include "BPFInstrInfo.h"
23 #include "BPFTargetMachine.h"
24 #include "llvm/ADT/Statistic.h"
25 #include "llvm/CodeGen/MachineInstrBuilder.h"
26 #include "llvm/CodeGen/MachineRegisterInfo.h"
27 
28 using namespace llvm;
29 
30 #define DEBUG_TYPE "bpf-mi-promotion-elim"
31 
32 STATISTIC(CmpPromotionElemNum, "Number of shifts for CMP promotion eliminated");
33 
34 namespace {
35 
36 struct BPFMIPeephole : public MachineFunctionPass {
37 
38   static char ID;
39   const BPFInstrInfo *TII;
40   MachineFunction *MF;
41   MachineRegisterInfo *MRI;
42 
43   BPFMIPeephole() : MachineFunctionPass(ID) {
44     initializeBPFMIPeepholePass(*PassRegistry::getPassRegistry());
45   }
46 
47 private:
48   // Initialize class variables.
49   void initialize(MachineFunction &MFParm);
50 
51   bool eliminateCmpPromotionSeq(void);
52   MachineInstr *getInsnDefZExtSubReg(unsigned Reg) const;
53   void updateInsnSeq(MachineBasicBlock &MBB, MachineInstr &MI,
54                      unsigned Reg) const;
55 
56 public:
57 
58   // Main entry point for this pass.
59   bool runOnMachineFunction(MachineFunction &MF) override {
60     if (skipFunction(MF.getFunction()))
61       return false;
62 
63     initialize(MF);
64 
65     return eliminateCmpPromotionSeq();
66   }
67 };
68 
69 // Initialize class variables.
70 void BPFMIPeephole::initialize(MachineFunction &MFParm) {
71   MF = &MFParm;
72   MRI = &MF->getRegInfo();
73   TII = MF->getSubtarget<BPFSubtarget>().getInstrInfo();
74   DEBUG(dbgs() << "*** BPF MI peephole pass ***\n\n");
75 }
76 
77 MachineInstr *BPFMIPeephole::getInsnDefZExtSubReg(unsigned Reg) const {
78   MachineInstr *Insn = MRI->getVRegDef(Reg);
79 
80   if (!Insn ||
81       Insn->isPHI() ||
82       Insn->getOpcode() != BPF::SRL_ri ||
83       Insn->getOperand(2).getImm() != 32)
84     return nullptr;
85 
86   Insn = MRI->getVRegDef(Insn->getOperand(1).getReg());
87   if (!Insn ||
88       Insn->isPHI() ||
89       Insn->getOpcode() != BPF::SLL_ri ||
90       Insn->getOperand(2).getImm() != 32)
91     return nullptr;
92 
93   Insn = MRI->getVRegDef(Insn->getOperand(1).getReg());
94   if (!Insn ||
95       Insn->isPHI() ||
96       Insn->getOpcode() != BPF::MOV_32_64)
97     return nullptr;
98 
99   return Insn;
100 }
101 
102 void
103 BPFMIPeephole::updateInsnSeq(MachineBasicBlock &MBB, MachineInstr &MI,
104                              unsigned Reg) const {
105   MachineInstr *Mov, *Lshift, *Rshift;
106   unsigned SubReg;
107   DebugLoc DL;
108 
109   Rshift = MRI->getVRegDef(Reg);
110   Lshift = MRI->getVRegDef(Rshift->getOperand(1).getReg());
111   Mov = MRI->getVRegDef(Lshift->getOperand(1).getReg());
112   SubReg = Mov->getOperand(1).getReg();
113   DL = MI.getDebugLoc();
114   BuildMI(MBB, Rshift, DL, TII->get(BPF::SUBREG_TO_REG), Reg)
115     .addImm(0).addReg(SubReg).addImm(BPF::sub_32);
116   Rshift->eraseFromParent();
117   Lshift->eraseFromParent();
118   Mov->eraseFromParent();
119 
120   CmpPromotionElemNum++;
121 }
122 
123 bool BPFMIPeephole::eliminateCmpPromotionSeq(void) {
124   bool Eliminated = false;
125   MachineInstr *Mov;
126   unsigned Reg;
127 
128   for (MachineBasicBlock &MBB : *MF) {
129     for (MachineInstr &MI : MBB) {
130       switch (MI.getOpcode()) {
131       default:
132         break;
133       case BPF::JUGT_rr:
134       case BPF::JUGE_rr:
135       case BPF::JULT_rr:
136       case BPF::JULE_rr:
137       case BPF::JEQ_rr:
138       case BPF::JNE_rr:
139         Reg = MI.getOperand(1).getReg();
140         Mov = getInsnDefZExtSubReg(Reg);
141         if (!Mov)
142           break;
143 
144 	updateInsnSeq(MBB, MI, Reg);
145 	Eliminated = true;
146 
147         // Fallthrough
148       case BPF::JUGT_ri:
149       case BPF::JUGE_ri:
150       case BPF::JULT_ri:
151       case BPF::JULE_ri:
152       case BPF::JEQ_ri:
153       case BPF::JNE_ri:
154         Reg = MI.getOperand(0).getReg();
155         Mov = getInsnDefZExtSubReg(Reg);
156         if (!Mov)
157           break;
158 
159 	updateInsnSeq(MBB, MI, Reg);
160 	Eliminated = true;
161         break;
162       }
163     }
164   }
165 
166   return Eliminated;
167 }
168 
169 } // end default namespace
170 
171 INITIALIZE_PASS(BPFMIPeephole, DEBUG_TYPE, "BPF MI Peephole Optimization",
172                 false, false)
173 
174 char BPFMIPeephole::ID = 0;
175 FunctionPass* llvm::createBPFMIPeepholePass() { return new BPFMIPeephole(); }
176