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"
34 #define DEBUG_TYPE "bpf-mi-zext-elim"
36 STATISTIC(ZExtElemNum
, "Number of zero extension shifts eliminated");
40 struct BPFMIPeephole
: public MachineFunctionPass
{
43 const BPFInstrInfo
*TII
;
45 MachineRegisterInfo
*MRI
;
47 BPFMIPeephole() : MachineFunctionPass(ID
) {
48 initializeBPFMIPeepholePass(*PassRegistry::getPassRegistry());
52 // Initialize class variables.
53 void initialize(MachineFunction
&MFParm
);
55 bool isCopyFrom32Def(MachineInstr
*CopyMI
);
56 bool isInsnFrom32Def(MachineInstr
*DefInsn
);
57 bool isPhiFrom32Def(MachineInstr
*MovMI
);
58 bool isMovFrom32Def(MachineInstr
*MovMI
);
59 bool eliminateZExtSeq(void);
60 bool eliminateZExt(void);
62 std::set
<MachineInstr
*> PhiInsns
;
66 // Main entry point for this pass.
67 bool runOnMachineFunction(MachineFunction
&MF
) override
{
68 if (skipFunction(MF
.getFunction()))
73 // First try to eliminate (zext, lshift, rshift) and then
74 // try to eliminate zext.
75 bool ZExtSeqExist
, ZExtExist
;
76 ZExtSeqExist
= eliminateZExtSeq();
77 ZExtExist
= eliminateZExt();
78 return ZExtSeqExist
|| ZExtExist
;
82 // Initialize class variables.
83 void BPFMIPeephole::initialize(MachineFunction
&MFParm
) {
85 MRI
= &MF
->getRegInfo();
86 TII
= MF
->getSubtarget
<BPFSubtarget
>().getInstrInfo();
87 LLVM_DEBUG(dbgs() << "*** BPF MachineSSA ZEXT Elim peephole pass ***\n\n");
90 bool BPFMIPeephole::isCopyFrom32Def(MachineInstr
*CopyMI
)
92 MachineOperand
&opnd
= CopyMI
->getOperand(1);
97 // Return false if getting value from a 32bit physical register.
98 // Most likely, this physical register is aliased to
99 // function call return value or current function parameters.
100 Register Reg
= opnd
.getReg();
101 if (!Register::isVirtualRegister(Reg
))
104 if (MRI
->getRegClass(Reg
) == &BPF::GPRRegClass
)
107 MachineInstr
*DefInsn
= MRI
->getVRegDef(Reg
);
108 if (!isInsnFrom32Def(DefInsn
))
114 bool BPFMIPeephole::isPhiFrom32Def(MachineInstr
*PhiMI
)
116 for (unsigned i
= 1, e
= PhiMI
->getNumOperands(); i
< e
; i
+= 2) {
117 MachineOperand
&opnd
= PhiMI
->getOperand(i
);
122 MachineInstr
*PhiDef
= MRI
->getVRegDef(opnd
.getReg());
125 if (PhiDef
->isPHI()) {
126 if (PhiInsns
.find(PhiDef
) != PhiInsns
.end())
128 PhiInsns
.insert(PhiDef
);
129 if (!isPhiFrom32Def(PhiDef
))
132 if (PhiDef
->getOpcode() == BPF::COPY
&& !isCopyFrom32Def(PhiDef
))
139 // The \p DefInsn instruction defines a virtual register.
140 bool BPFMIPeephole::isInsnFrom32Def(MachineInstr
*DefInsn
)
145 if (DefInsn
->isPHI()) {
146 if (PhiInsns
.find(DefInsn
) != PhiInsns
.end())
148 PhiInsns
.insert(DefInsn
);
149 if (!isPhiFrom32Def(DefInsn
))
151 } else if (DefInsn
->getOpcode() == BPF::COPY
) {
152 if (!isCopyFrom32Def(DefInsn
))
159 bool BPFMIPeephole::isMovFrom32Def(MachineInstr
*MovMI
)
161 MachineInstr
*DefInsn
= MRI
->getVRegDef(MovMI
->getOperand(1).getReg());
163 LLVM_DEBUG(dbgs() << " Def of Mov Src:");
164 LLVM_DEBUG(DefInsn
->dump());
167 if (!isInsnFrom32Def(DefInsn
))
170 LLVM_DEBUG(dbgs() << " One ZExt elim sequence identified.\n");
175 bool BPFMIPeephole::eliminateZExtSeq(void) {
176 MachineInstr
* ToErase
= nullptr;
177 bool Eliminated
= false;
179 for (MachineBasicBlock
&MBB
: *MF
) {
180 for (MachineInstr
&MI
: MBB
) {
181 // If the previous instruction was marked for elimination, remove it now.
183 ToErase
->eraseFromParent();
187 // Eliminate the 32-bit to 64-bit zero extension sequence when possible.
192 if (MI
.getOpcode() == BPF::SRL_ri
&&
193 MI
.getOperand(2).getImm() == 32) {
194 Register DstReg
= MI
.getOperand(0).getReg();
195 Register ShfReg
= MI
.getOperand(1).getReg();
196 MachineInstr
*SllMI
= MRI
->getVRegDef(ShfReg
);
198 LLVM_DEBUG(dbgs() << "Starting SRL found:");
199 LLVM_DEBUG(MI
.dump());
203 SllMI
->getOpcode() != BPF::SLL_ri
||
204 SllMI
->getOperand(2).getImm() != 32)
207 LLVM_DEBUG(dbgs() << " SLL found:");
208 LLVM_DEBUG(SllMI
->dump());
210 MachineInstr
*MovMI
= MRI
->getVRegDef(SllMI
->getOperand(1).getReg());
213 MovMI
->getOpcode() != BPF::MOV_32_64
)
216 LLVM_DEBUG(dbgs() << " Type cast Mov found:");
217 LLVM_DEBUG(MovMI
->dump());
219 Register SubReg
= MovMI
->getOperand(1).getReg();
220 if (!isMovFrom32Def(MovMI
)) {
222 << " One ZExt elim sequence failed qualifying elim.\n");
226 BuildMI(MBB
, MI
, MI
.getDebugLoc(), TII
->get(BPF::SUBREG_TO_REG
), DstReg
)
227 .addImm(0).addReg(SubReg
).addImm(BPF::sub_32
);
229 SllMI
->eraseFromParent();
230 MovMI
->eraseFromParent();
231 // MI is the right shift, we can't erase it in it's own iteration.
232 // Mark it to ToErase, and erase in the next iteration.
243 bool BPFMIPeephole::eliminateZExt(void) {
244 MachineInstr
* ToErase
= nullptr;
245 bool Eliminated
= false;
247 for (MachineBasicBlock
&MBB
: *MF
) {
248 for (MachineInstr
&MI
: MBB
) {
249 // If the previous instruction was marked for elimination, remove it now.
251 ToErase
->eraseFromParent();
255 if (MI
.getOpcode() != BPF::MOV_32_64
)
258 // Eliminate MOV_32_64 if possible.
261 // If wB has been zero extended, replace it with a SUBREG_TO_REG.
262 // This is to workaround BPF programs where pkt->{data, data_end}
263 // is encoded as u32, but actually the verifier populates them
264 // as 64bit pointer. The MOV_32_64 will zero out the top 32 bits.
265 LLVM_DEBUG(dbgs() << "Candidate MOV_32_64 instruction:");
266 LLVM_DEBUG(MI
.dump());
268 if (!isMovFrom32Def(&MI
))
271 LLVM_DEBUG(dbgs() << "Removing the MOV_32_64 instruction\n");
273 Register dst
= MI
.getOperand(0).getReg();
274 Register src
= MI
.getOperand(1).getReg();
276 // Build a SUBREG_TO_REG instruction.
277 BuildMI(MBB
, MI
, MI
.getDebugLoc(), TII
->get(BPF::SUBREG_TO_REG
), dst
)
278 .addImm(0).addReg(src
).addImm(BPF::sub_32
);
288 } // end default namespace
290 INITIALIZE_PASS(BPFMIPeephole
, DEBUG_TYPE
,
291 "BPF MachineSSA Peephole Optimization For ZEXT Eliminate",
294 char BPFMIPeephole::ID
= 0;
295 FunctionPass
* llvm::createBPFMIPeepholePass() { return new BPFMIPeephole(); }
297 STATISTIC(RedundantMovElemNum
, "Number of redundant moves eliminated");
301 struct BPFMIPreEmitPeephole
: public MachineFunctionPass
{
305 const TargetRegisterInfo
*TRI
;
307 BPFMIPreEmitPeephole() : MachineFunctionPass(ID
) {
308 initializeBPFMIPreEmitPeepholePass(*PassRegistry::getPassRegistry());
312 // Initialize class variables.
313 void initialize(MachineFunction
&MFParm
);
315 bool eliminateRedundantMov(void);
319 // Main entry point for this pass.
320 bool runOnMachineFunction(MachineFunction
&MF
) override
{
321 if (skipFunction(MF
.getFunction()))
326 return eliminateRedundantMov();
330 // Initialize class variables.
331 void BPFMIPreEmitPeephole::initialize(MachineFunction
&MFParm
) {
333 TRI
= MF
->getSubtarget
<BPFSubtarget
>().getRegisterInfo();
334 LLVM_DEBUG(dbgs() << "*** BPF PreEmit peephole pass ***\n\n");
337 bool BPFMIPreEmitPeephole::eliminateRedundantMov(void) {
338 MachineInstr
* ToErase
= nullptr;
339 bool Eliminated
= false;
341 for (MachineBasicBlock
&MBB
: *MF
) {
342 for (MachineInstr
&MI
: MBB
) {
343 // If the previous instruction was marked for elimination, remove it now.
345 LLVM_DEBUG(dbgs() << " Redundant Mov Eliminated:");
346 LLVM_DEBUG(ToErase
->dump());
347 ToErase
->eraseFromParent();
351 // Eliminate identical move:
355 // Note that we cannot remove
358 // as these two instructions having side effects, zeroing out
359 // top 32 bits of rA.
360 unsigned Opcode
= MI
.getOpcode();
361 if (Opcode
== BPF::MOV_rr
) {
362 Register dst
= MI
.getOperand(0).getReg();
363 Register src
= MI
.getOperand(1).getReg();
369 RedundantMovElemNum
++;
378 } // end default namespace
380 INITIALIZE_PASS(BPFMIPreEmitPeephole
, "bpf-mi-pemit-peephole",
381 "BPF PreEmit Peephole Optimization", false, false)
383 char BPFMIPreEmitPeephole::ID
= 0;
384 FunctionPass
* llvm::createBPFMIPreEmitPeepholePass()
386 return new BPFMIPreEmitPeephole();
389 STATISTIC(TruncElemNum
, "Number of truncation eliminated");
393 struct BPFMIPeepholeTruncElim
: public MachineFunctionPass
{
396 const BPFInstrInfo
*TII
;
398 MachineRegisterInfo
*MRI
;
400 BPFMIPeepholeTruncElim() : MachineFunctionPass(ID
) {
401 initializeBPFMIPeepholeTruncElimPass(*PassRegistry::getPassRegistry());
405 // Initialize class variables.
406 void initialize(MachineFunction
&MFParm
);
408 bool eliminateTruncSeq(void);
412 // Main entry point for this pass.
413 bool runOnMachineFunction(MachineFunction
&MF
) override
{
414 if (skipFunction(MF
.getFunction()))
419 return eliminateTruncSeq();
423 static bool TruncSizeCompatible(int TruncSize
, unsigned opcode
)
426 return opcode
== BPF::LDB
|| opcode
== BPF::LDB32
;
429 return opcode
== BPF::LDH
|| opcode
== BPF::LDH32
;
432 return opcode
== BPF::LDW
|| opcode
== BPF::LDW32
;
437 // Initialize class variables.
438 void BPFMIPeepholeTruncElim::initialize(MachineFunction
&MFParm
) {
440 MRI
= &MF
->getRegInfo();
441 TII
= MF
->getSubtarget
<BPFSubtarget
>().getInstrInfo();
442 LLVM_DEBUG(dbgs() << "*** BPF MachineSSA TRUNC Elim peephole pass ***\n\n");
445 // Reg truncating is often the result of 8/16/32bit->64bit or
446 // 8/16bit->32bit conversion. If the reg value is loaded with
447 // masked byte width, the AND operation can be removed since
448 // BPF LOAD already has zero extension.
450 // This also solved a correctness issue.
451 // In BPF socket-related program, e.g., __sk_buff->{data, data_end}
452 // are 32-bit registers, but later on, kernel verifier will rewrite
453 // it with 64-bit value. Therefore, truncating the value after the
454 // load will result in incorrect code.
455 bool BPFMIPeepholeTruncElim::eliminateTruncSeq(void) {
456 MachineInstr
* ToErase
= nullptr;
457 bool Eliminated
= false;
459 for (MachineBasicBlock
&MBB
: *MF
) {
460 for (MachineInstr
&MI
: MBB
) {
461 // The second insn to remove if the eliminate candidate is a pair.
462 MachineInstr
*MI2
= nullptr;
463 Register DstReg
, SrcReg
;
467 // If the previous instruction was marked for elimination, remove it now.
469 ToErase
->eraseFromParent();
473 // AND A, 0xFFFFFFFF will be turned into SLL/SRL pair due to immediate
474 // for BPF ANDI is i32, and this case only happens on ALU64.
475 if (MI
.getOpcode() == BPF::SRL_ri
&&
476 MI
.getOperand(2).getImm() == 32) {
477 SrcReg
= MI
.getOperand(1).getReg();
478 if (!MRI
->hasOneNonDBGUse(SrcReg
))
481 MI2
= MRI
->getVRegDef(SrcReg
);
482 DstReg
= MI
.getOperand(0).getReg();
485 MI2
->getOpcode() != BPF::SLL_ri
||
486 MI2
->getOperand(2).getImm() != 32)
490 SrcReg
= MI2
->getOperand(1).getReg();
491 DefMI
= MRI
->getVRegDef(SrcReg
);
494 } else if (MI
.getOpcode() == BPF::AND_ri
||
495 MI
.getOpcode() == BPF::AND_ri_32
) {
496 SrcReg
= MI
.getOperand(1).getReg();
497 DstReg
= MI
.getOperand(0).getReg();
498 DefMI
= MRI
->getVRegDef(SrcReg
);
503 int64_t imm
= MI
.getOperand(2).getImm();
506 else if (imm
== 0xffff)
513 // The definition is PHI node, check all inputs.
514 if (DefMI
->isPHI()) {
515 bool CheckFail
= false;
517 for (unsigned i
= 1, e
= DefMI
->getNumOperands(); i
< e
; i
+= 2) {
518 MachineOperand
&opnd
= DefMI
->getOperand(i
);
524 MachineInstr
*PhiDef
= MRI
->getVRegDef(opnd
.getReg());
525 if (!PhiDef
|| PhiDef
->isPHI() ||
526 !TruncSizeCompatible(TruncSize
, PhiDef
->getOpcode())) {
534 } else if (!TruncSizeCompatible(TruncSize
, DefMI
->getOpcode())) {
538 BuildMI(MBB
, MI
, MI
.getDebugLoc(), TII
->get(BPF::MOV_rr
), DstReg
)
542 MI2
->eraseFromParent();
544 // Mark it to ToErase, and erase in the next iteration.
554 } // end default namespace
556 INITIALIZE_PASS(BPFMIPeepholeTruncElim
, "bpf-mi-trunc-elim",
557 "BPF MachineSSA Peephole Optimization For TRUNC Eliminate",
560 char BPFMIPeepholeTruncElim::ID
= 0;
561 FunctionPass
* llvm::createBPFMIPeepholeTruncElimPass()
563 return new BPFMIPeepholeTruncElim();