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   Insn = MRI->getVRegDef(Insn->getOperand(1).getReg());
100   if (!Insn || Insn->isPHI())
101     return nullptr;
102 
103   if (Insn->getOpcode() == BPF::COPY) {
104     MachineOperand &opnd = Insn->getOperand(1);
105 
106     if (!opnd.isReg())
107       return nullptr;
108 
109     unsigned Reg = opnd.getReg();
110     if ((TargetRegisterInfo::isVirtualRegister(Reg) &&
111          MRI->getRegClass(Reg) == &BPF::GPRRegClass) ||
112         (TargetRegisterInfo::isPhysicalRegister(Reg) &&
113          BPF::GPRRegClass.contains(Reg)))
114       return nullptr;
115   }
116 
117   return Insn;
118 }
119 
120 void
121 BPFMIPeephole::updateInsnSeq(MachineBasicBlock &MBB, MachineInstr &MI,
122                              unsigned Reg) const {
123   MachineInstr *Mov, *Lshift, *Rshift;
124   unsigned SubReg;
125   DebugLoc DL;
126 
127   Rshift = MRI->getVRegDef(Reg);
128   Lshift = MRI->getVRegDef(Rshift->getOperand(1).getReg());
129   Mov = MRI->getVRegDef(Lshift->getOperand(1).getReg());
130   SubReg = Mov->getOperand(1).getReg();
131   DL = MI.getDebugLoc();
132   BuildMI(MBB, Rshift, DL, TII->get(BPF::SUBREG_TO_REG), Reg)
133     .addImm(0).addReg(SubReg).addImm(BPF::sub_32);
134   Rshift->eraseFromParent();
135   Lshift->eraseFromParent();
136   Mov->eraseFromParent();
137 
138   CmpPromotionElemNum++;
139 }
140 
141 bool BPFMIPeephole::eliminateCmpPromotionSeq(void) {
142   bool Eliminated = false;
143   MachineInstr *Mov;
144   unsigned Reg;
145 
146   for (MachineBasicBlock &MBB : *MF) {
147     for (MachineInstr &MI : MBB) {
148       switch (MI.getOpcode()) {
149       default:
150         break;
151       case BPF::JUGT_rr:
152       case BPF::JUGE_rr:
153       case BPF::JULT_rr:
154       case BPF::JULE_rr:
155       case BPF::JEQ_rr:
156       case BPF::JNE_rr:
157         Reg = MI.getOperand(1).getReg();
158         Mov = getInsnDefZExtSubReg(Reg);
159         if (Mov) {
160           updateInsnSeq(MBB, MI, Reg);
161           Eliminated = true;
162         }
163         // Fallthrough
164       case BPF::JUGT_ri:
165       case BPF::JUGE_ri:
166       case BPF::JULT_ri:
167       case BPF::JULE_ri:
168       case BPF::JEQ_ri:
169       case BPF::JNE_ri:
170         Reg = MI.getOperand(0).getReg();
171         Mov = getInsnDefZExtSubReg(Reg);
172         if (!Mov)
173           break;
174 
175 	updateInsnSeq(MBB, MI, Reg);
176 	Eliminated = true;
177         break;
178       }
179     }
180   }
181 
182   return Eliminated;
183 }
184 
185 } // end default namespace
186 
187 INITIALIZE_PASS(BPFMIPeephole, DEBUG_TYPE, "BPF MI Peephole Optimization",
188                 false, false)
189 
190 char BPFMIPeephole::ID = 0;
191 FunctionPass* llvm::createBPFMIPeepholePass() { return new BPFMIPeephole(); }
192