1 //===-------------- BPFMIPeephole.cpp - MI Peephole Cleanups -------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This pass performs peephole optimizations to cleanup ugly code sequences at
10 // MachineInstruction layer.
12 // Currently, there are two optimizations implemented:
13 // - One pre-RA MachineSSA pass to eliminate type promotion sequences, those
14 // zero extend 32-bit subregisters to 64-bit registers, if the compiler
15 // could prove the subregisters is defined by 32-bit operations in which
16 // case the upper half of the underlying 64-bit registers were zeroed
19 // - One post-RA PreEmit pass to do final cleanup on some redundant
20 // instructions generated due to bad RA on subregister.
21 //===----------------------------------------------------------------------===//
24 #include "BPFInstrInfo.h"
25 #include "BPFTargetMachine.h"
26 #include "llvm/ADT/Statistic.h"
27 #include "llvm/CodeGen/MachineInstrBuilder.h"
28 #include "llvm/CodeGen/MachineRegisterInfo.h"
29 #include "llvm/Support/Debug.h"
33 #define DEBUG_TYPE "bpf-mi-zext-elim"
35 STATISTIC(ZExtElemNum
, "Number of zero extension shifts eliminated");
39 struct BPFMIPeephole
: public MachineFunctionPass
{
42 const BPFInstrInfo
*TII
;
44 MachineRegisterInfo
*MRI
;
46 BPFMIPeephole() : MachineFunctionPass(ID
) {
47 initializeBPFMIPeepholePass(*PassRegistry::getPassRegistry());
51 // Initialize class variables.
52 void initialize(MachineFunction
&MFParm
);
54 bool isMovFrom32Def(MachineInstr
*MovMI
);
55 bool eliminateZExtSeq(void);
59 // Main entry point for this pass.
60 bool runOnMachineFunction(MachineFunction
&MF
) override
{
61 if (skipFunction(MF
.getFunction()))
66 return eliminateZExtSeq();
70 // Initialize class variables.
71 void BPFMIPeephole::initialize(MachineFunction
&MFParm
) {
73 MRI
= &MF
->getRegInfo();
74 TII
= MF
->getSubtarget
<BPFSubtarget
>().getInstrInfo();
75 LLVM_DEBUG(dbgs() << "*** BPF MachineSSA ZEXT Elim peephole pass ***\n\n");
78 bool BPFMIPeephole::isMovFrom32Def(MachineInstr
*MovMI
)
80 MachineInstr
*DefInsn
= MRI
->getVRegDef(MovMI
->getOperand(1).getReg());
82 LLVM_DEBUG(dbgs() << " Def of Mov Src:");
83 LLVM_DEBUG(DefInsn
->dump());
88 if (DefInsn
->isPHI()) {
89 for (unsigned i
= 1, e
= DefInsn
->getNumOperands(); i
< e
; i
+= 2) {
90 MachineOperand
&opnd
= DefInsn
->getOperand(i
);
95 MachineInstr
*PhiDef
= MRI
->getVRegDef(opnd
.getReg());
96 // quick check on PHI incoming definitions.
97 if (!PhiDef
|| PhiDef
->isPHI() || PhiDef
->getOpcode() == BPF::COPY
)
102 if (DefInsn
->getOpcode() == BPF::COPY
) {
103 MachineOperand
&opnd
= DefInsn
->getOperand(1);
108 Register Reg
= opnd
.getReg();
109 if ((Register::isVirtualRegister(Reg
) &&
110 MRI
->getRegClass(Reg
) == &BPF::GPRRegClass
))
114 LLVM_DEBUG(dbgs() << " One ZExt elim sequence identified.\n");
119 bool BPFMIPeephole::eliminateZExtSeq(void) {
120 MachineInstr
* ToErase
= nullptr;
121 bool Eliminated
= false;
123 for (MachineBasicBlock
&MBB
: *MF
) {
124 for (MachineInstr
&MI
: MBB
) {
125 // If the previous instruction was marked for elimination, remove it now.
127 ToErase
->eraseFromParent();
131 // Eliminate the 32-bit to 64-bit zero extension sequence when possible.
136 if (MI
.getOpcode() == BPF::SRL_ri
&&
137 MI
.getOperand(2).getImm() == 32) {
138 Register DstReg
= MI
.getOperand(0).getReg();
139 Register ShfReg
= MI
.getOperand(1).getReg();
140 MachineInstr
*SllMI
= MRI
->getVRegDef(ShfReg
);
142 LLVM_DEBUG(dbgs() << "Starting SRL found:");
143 LLVM_DEBUG(MI
.dump());
147 SllMI
->getOpcode() != BPF::SLL_ri
||
148 SllMI
->getOperand(2).getImm() != 32)
151 LLVM_DEBUG(dbgs() << " SLL found:");
152 LLVM_DEBUG(SllMI
->dump());
154 MachineInstr
*MovMI
= MRI
->getVRegDef(SllMI
->getOperand(1).getReg());
157 MovMI
->getOpcode() != BPF::MOV_32_64
)
160 LLVM_DEBUG(dbgs() << " Type cast Mov found:");
161 LLVM_DEBUG(MovMI
->dump());
163 Register SubReg
= MovMI
->getOperand(1).getReg();
164 if (!isMovFrom32Def(MovMI
)) {
166 << " One ZExt elim sequence failed qualifying elim.\n");
170 BuildMI(MBB
, MI
, MI
.getDebugLoc(), TII
->get(BPF::SUBREG_TO_REG
), DstReg
)
171 .addImm(0).addReg(SubReg
).addImm(BPF::sub_32
);
173 SllMI
->eraseFromParent();
174 MovMI
->eraseFromParent();
175 // MI is the right shift, we can't erase it in it's own iteration.
176 // Mark it to ToErase, and erase in the next iteration.
187 } // end default namespace
189 INITIALIZE_PASS(BPFMIPeephole
, DEBUG_TYPE
,
190 "BPF MachineSSA Peephole Optimization For ZEXT Eliminate",
193 char BPFMIPeephole::ID
= 0;
194 FunctionPass
* llvm::createBPFMIPeepholePass() { return new BPFMIPeephole(); }
196 STATISTIC(RedundantMovElemNum
, "Number of redundant moves eliminated");
200 struct BPFMIPreEmitPeephole
: public MachineFunctionPass
{
204 const TargetRegisterInfo
*TRI
;
206 BPFMIPreEmitPeephole() : MachineFunctionPass(ID
) {
207 initializeBPFMIPreEmitPeepholePass(*PassRegistry::getPassRegistry());
211 // Initialize class variables.
212 void initialize(MachineFunction
&MFParm
);
214 bool eliminateRedundantMov(void);
218 // Main entry point for this pass.
219 bool runOnMachineFunction(MachineFunction
&MF
) override
{
220 if (skipFunction(MF
.getFunction()))
225 return eliminateRedundantMov();
229 // Initialize class variables.
230 void BPFMIPreEmitPeephole::initialize(MachineFunction
&MFParm
) {
232 TRI
= MF
->getSubtarget
<BPFSubtarget
>().getRegisterInfo();
233 LLVM_DEBUG(dbgs() << "*** BPF PreEmit peephole pass ***\n\n");
236 bool BPFMIPreEmitPeephole::eliminateRedundantMov(void) {
237 MachineInstr
* ToErase
= nullptr;
238 bool Eliminated
= false;
240 for (MachineBasicBlock
&MBB
: *MF
) {
241 for (MachineInstr
&MI
: MBB
) {
242 // If the previous instruction was marked for elimination, remove it now.
244 LLVM_DEBUG(dbgs() << " Redundant Mov Eliminated:");
245 LLVM_DEBUG(ToErase
->dump());
246 ToErase
->eraseFromParent();
250 // Eliminate identical move:
254 // This is particularly possible to happen when sub-register support
255 // enabled. The special type cast insn MOV_32_64 involves different
256 // register class on src (i32) and dst (i64), RA could generate useless
257 // instruction due to this.
258 unsigned Opcode
= MI
.getOpcode();
259 if (Opcode
== BPF::MOV_32_64
||
260 Opcode
== BPF::MOV_rr
|| Opcode
== BPF::MOV_rr_32
) {
261 Register dst
= MI
.getOperand(0).getReg();
262 Register src
= MI
.getOperand(1).getReg();
264 if (Opcode
== BPF::MOV_32_64
)
265 dst
= TRI
->getSubReg(dst
, BPF::sub_32
);
271 RedundantMovElemNum
++;
280 } // end default namespace
282 INITIALIZE_PASS(BPFMIPreEmitPeephole
, "bpf-mi-pemit-peephole",
283 "BPF PreEmit Peephole Optimization", false, false)
285 char BPFMIPreEmitPeephole::ID
= 0;
286 FunctionPass
* llvm::createBPFMIPreEmitPeepholePass()
288 return new BPFMIPreEmitPeephole();
291 STATISTIC(TruncElemNum
, "Number of truncation eliminated");
295 struct BPFMIPeepholeTruncElim
: public MachineFunctionPass
{
298 const BPFInstrInfo
*TII
;
300 MachineRegisterInfo
*MRI
;
302 BPFMIPeepholeTruncElim() : MachineFunctionPass(ID
) {
303 initializeBPFMIPeepholeTruncElimPass(*PassRegistry::getPassRegistry());
307 // Initialize class variables.
308 void initialize(MachineFunction
&MFParm
);
310 bool eliminateTruncSeq(void);
314 // Main entry point for this pass.
315 bool runOnMachineFunction(MachineFunction
&MF
) override
{
316 if (skipFunction(MF
.getFunction()))
321 return eliminateTruncSeq();
325 static bool TruncSizeCompatible(int TruncSize
, unsigned opcode
)
328 return opcode
== BPF::LDB
|| opcode
== BPF::LDB32
;
331 return opcode
== BPF::LDH
|| opcode
== BPF::LDH32
;
334 return opcode
== BPF::LDW
|| opcode
== BPF::LDW32
;
339 // Initialize class variables.
340 void BPFMIPeepholeTruncElim::initialize(MachineFunction
&MFParm
) {
342 MRI
= &MF
->getRegInfo();
343 TII
= MF
->getSubtarget
<BPFSubtarget
>().getInstrInfo();
344 LLVM_DEBUG(dbgs() << "*** BPF MachineSSA TRUNC Elim peephole pass ***\n\n");
347 // Reg truncating is often the result of 8/16/32bit->64bit or
348 // 8/16bit->32bit conversion. If the reg value is loaded with
349 // masked byte width, the AND operation can be removed since
350 // BPF LOAD already has zero extension.
352 // This also solved a correctness issue.
353 // In BPF socket-related program, e.g., __sk_buff->{data, data_end}
354 // are 32-bit registers, but later on, kernel verifier will rewrite
355 // it with 64-bit value. Therefore, truncating the value after the
356 // load will result in incorrect code.
357 bool BPFMIPeepholeTruncElim::eliminateTruncSeq(void) {
358 MachineInstr
* ToErase
= nullptr;
359 bool Eliminated
= false;
361 for (MachineBasicBlock
&MBB
: *MF
) {
362 for (MachineInstr
&MI
: MBB
) {
363 // The second insn to remove if the eliminate candidate is a pair.
364 MachineInstr
*MI2
= nullptr;
365 Register DstReg
, SrcReg
;
369 // If the previous instruction was marked for elimination, remove it now.
371 ToErase
->eraseFromParent();
375 // AND A, 0xFFFFFFFF will be turned into SLL/SRL pair due to immediate
376 // for BPF ANDI is i32, and this case only happens on ALU64.
377 if (MI
.getOpcode() == BPF::SRL_ri
&&
378 MI
.getOperand(2).getImm() == 32) {
379 SrcReg
= MI
.getOperand(1).getReg();
380 MI2
= MRI
->getVRegDef(SrcReg
);
381 DstReg
= MI
.getOperand(0).getReg();
384 MI2
->getOpcode() != BPF::SLL_ri
||
385 MI2
->getOperand(2).getImm() != 32)
389 SrcReg
= MI2
->getOperand(1).getReg();
390 DefMI
= MRI
->getVRegDef(SrcReg
);
393 } else if (MI
.getOpcode() == BPF::AND_ri
||
394 MI
.getOpcode() == BPF::AND_ri_32
) {
395 SrcReg
= MI
.getOperand(1).getReg();
396 DstReg
= MI
.getOperand(0).getReg();
397 DefMI
= MRI
->getVRegDef(SrcReg
);
402 int64_t imm
= MI
.getOperand(2).getImm();
405 else if (imm
== 0xffff)
412 // The definition is PHI node, check all inputs.
413 if (DefMI
->isPHI()) {
414 bool CheckFail
= false;
416 for (unsigned i
= 1, e
= DefMI
->getNumOperands(); i
< e
; i
+= 2) {
417 MachineOperand
&opnd
= DefMI
->getOperand(i
);
423 MachineInstr
*PhiDef
= MRI
->getVRegDef(opnd
.getReg());
424 if (!PhiDef
|| PhiDef
->isPHI() ||
425 !TruncSizeCompatible(TruncSize
, PhiDef
->getOpcode())) {
433 } else if (!TruncSizeCompatible(TruncSize
, DefMI
->getOpcode())) {
437 BuildMI(MBB
, MI
, MI
.getDebugLoc(), TII
->get(BPF::MOV_rr
), DstReg
)
441 MI2
->eraseFromParent();
443 // Mark it to ToErase, and erase in the next iteration.
453 } // end default namespace
455 INITIALIZE_PASS(BPFMIPeepholeTruncElim
, "bpf-mi-trunc-elim",
456 "BPF MachineSSA Peephole Optimization For TRUNC Eliminate",
459 char BPFMIPeepholeTruncElim::ID
= 0;
460 FunctionPass
* llvm::createBPFMIPeepholeTruncElimPass()
462 return new BPFMIPeepholeTruncElim();