blob: a2ceade66800c597d19a5de7957f23f28dfab32f [file] [log] [blame]
Yonghong Song60fed1f2018-02-23 23:49:32 +00001//===-------------- BPFMIPeephole.cpp - MI Peephole Cleanups -------------===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Yonghong Song60fed1f2018-02-23 23:49:32 +00006//
7//===----------------------------------------------------------------------===//
8//
9// This pass performs peephole optimizations to cleanup ugly code sequences at
10// MachineInstruction layer.
11//
Yonghong Songe91802f2018-03-13 06:47:06 +000012// 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
17// implicitly.
Yonghong Song60fed1f2018-02-23 23:49:32 +000018//
Yonghong Songe91802f2018-03-13 06:47:06 +000019// - One post-RA PreEmit pass to do final cleanup on some redundant
20// instructions generated due to bad RA on subregister.
Yonghong Song60fed1f2018-02-23 23:49:32 +000021//===----------------------------------------------------------------------===//
22
23#include "BPF.h"
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"
Reid Kleckner904cd3e2019-10-19 01:31:09 +000029#include "llvm/Support/Debug.h"
Simon Pilgrima88cc202020-04-10 16:23:55 +010030#include <set>
Yonghong Song60fed1f2018-02-23 23:49:32 +000031
32using namespace llvm;
33
Yonghong Songc88bcde2018-03-13 06:47:03 +000034#define DEBUG_TYPE "bpf-mi-zext-elim"
Yonghong Song60fed1f2018-02-23 23:49:32 +000035
Yonghong Songc88bcde2018-03-13 06:47:03 +000036STATISTIC(ZExtElemNum, "Number of zero extension shifts eliminated");
Yonghong Song60fed1f2018-02-23 23:49:32 +000037
38namespace {
39
40struct BPFMIPeephole : public MachineFunctionPass {
41
42 static char ID;
43 const BPFInstrInfo *TII;
44 MachineFunction *MF;
45 MachineRegisterInfo *MRI;
46
47 BPFMIPeephole() : MachineFunctionPass(ID) {
48 initializeBPFMIPeepholePass(*PassRegistry::getPassRegistry());
49 }
50
51private:
52 // Initialize class variables.
53 void initialize(MachineFunction &MFParm);
54
Yonghong Songa0841df2019-11-20 09:52:29 -080055 bool isCopyFrom32Def(MachineInstr *CopyMI);
56 bool isInsnFrom32Def(MachineInstr *DefInsn);
57 bool isPhiFrom32Def(MachineInstr *MovMI);
Yonghong Songc88bcde2018-03-13 06:47:03 +000058 bool isMovFrom32Def(MachineInstr *MovMI);
59 bool eliminateZExtSeq(void);
Yonghong Song60fed1f2018-02-23 23:49:32 +000060
Yonghong Song9e6aa812019-11-22 00:20:10 -080061 std::set<MachineInstr *> PhiInsns;
62
Yonghong Song60fed1f2018-02-23 23:49:32 +000063public:
64
65 // Main entry point for this pass.
66 bool runOnMachineFunction(MachineFunction &MF) override {
67 if (skipFunction(MF.getFunction()))
68 return false;
69
70 initialize(MF);
71
Yonghong Songc88bcde2018-03-13 06:47:03 +000072 return eliminateZExtSeq();
Yonghong Song60fed1f2018-02-23 23:49:32 +000073 }
74};
75
76// Initialize class variables.
77void BPFMIPeephole::initialize(MachineFunction &MFParm) {
78 MF = &MFParm;
79 MRI = &MF->getRegInfo();
80 TII = MF->getSubtarget<BPFSubtarget>().getInstrInfo();
Jiong Wangec518512019-10-16 15:27:59 +000081 LLVM_DEBUG(dbgs() << "*** BPF MachineSSA ZEXT Elim peephole pass ***\n\n");
Yonghong Song60fed1f2018-02-23 23:49:32 +000082}
83
Yonghong Songa0841df2019-11-20 09:52:29 -080084bool BPFMIPeephole::isCopyFrom32Def(MachineInstr *CopyMI)
85{
86 MachineOperand &opnd = CopyMI->getOperand(1);
87
88 if (!opnd.isReg())
89 return false;
90
91 // Return false if getting value from a 32bit physical register.
92 // Most likely, this physical register is aliased to
93 // function call return value or current function parameters.
94 Register Reg = opnd.getReg();
95 if (!Register::isVirtualRegister(Reg))
96 return false;
97
98 if (MRI->getRegClass(Reg) == &BPF::GPRRegClass)
99 return false;
100
101 MachineInstr *DefInsn = MRI->getVRegDef(Reg);
102 if (!isInsnFrom32Def(DefInsn))
103 return false;
104
105 return true;
106}
107
108bool BPFMIPeephole::isPhiFrom32Def(MachineInstr *PhiMI)
109{
110 for (unsigned i = 1, e = PhiMI->getNumOperands(); i < e; i += 2) {
111 MachineOperand &opnd = PhiMI->getOperand(i);
112
113 if (!opnd.isReg())
114 return false;
115
116 MachineInstr *PhiDef = MRI->getVRegDef(opnd.getReg());
117 if (!PhiDef)
118 return false;
Yonghong Song9e6aa812019-11-22 00:20:10 -0800119 if (PhiDef->isPHI()) {
120 if (PhiInsns.find(PhiDef) != PhiInsns.end())
121 return false;
122 PhiInsns.insert(PhiDef);
123 if (!isPhiFrom32Def(PhiDef))
124 return false;
125 }
Yonghong Songa0841df2019-11-20 09:52:29 -0800126 if (PhiDef->getOpcode() == BPF::COPY && !isCopyFrom32Def(PhiDef))
127 return false;
128 }
129
130 return true;
131}
132
133// The \p DefInsn instruction defines a virtual register.
134bool BPFMIPeephole::isInsnFrom32Def(MachineInstr *DefInsn)
135{
136 if (!DefInsn)
137 return false;
138
139 if (DefInsn->isPHI()) {
Yonghong Song9e6aa812019-11-22 00:20:10 -0800140 if (PhiInsns.find(DefInsn) != PhiInsns.end())
141 return false;
142 PhiInsns.insert(DefInsn);
Yonghong Songa0841df2019-11-20 09:52:29 -0800143 if (!isPhiFrom32Def(DefInsn))
144 return false;
145 } else if (DefInsn->getOpcode() == BPF::COPY) {
146 if (!isCopyFrom32Def(DefInsn))
147 return false;
148 }
149
150 return true;
151}
152
Yonghong Songc88bcde2018-03-13 06:47:03 +0000153bool BPFMIPeephole::isMovFrom32Def(MachineInstr *MovMI)
154{
155 MachineInstr *DefInsn = MRI->getVRegDef(MovMI->getOperand(1).getReg());
Yonghong Song60fed1f2018-02-23 23:49:32 +0000156
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000157 LLVM_DEBUG(dbgs() << " Def of Mov Src:");
158 LLVM_DEBUG(DefInsn->dump());
Yonghong Song82bf8bc2018-03-13 06:47:07 +0000159
Yonghong Song9e6aa812019-11-22 00:20:10 -0800160 PhiInsns.clear();
Yonghong Songa0841df2019-11-20 09:52:29 -0800161 if (!isInsnFrom32Def(DefInsn))
Yonghong Songc88bcde2018-03-13 06:47:03 +0000162 return false;
Yonghong Song60fed1f2018-02-23 23:49:32 +0000163
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000164 LLVM_DEBUG(dbgs() << " One ZExt elim sequence identified.\n");
Yonghong Song82bf8bc2018-03-13 06:47:07 +0000165
Yonghong Songc88bcde2018-03-13 06:47:03 +0000166 return true;
Yonghong Song60fed1f2018-02-23 23:49:32 +0000167}
168
Yonghong Songc88bcde2018-03-13 06:47:03 +0000169bool BPFMIPeephole::eliminateZExtSeq(void) {
170 MachineInstr* ToErase = nullptr;
Yonghong Song60fed1f2018-02-23 23:49:32 +0000171 bool Eliminated = false;
Yonghong Song60fed1f2018-02-23 23:49:32 +0000172
173 for (MachineBasicBlock &MBB : *MF) {
174 for (MachineInstr &MI : MBB) {
Yonghong Songc88bcde2018-03-13 06:47:03 +0000175 // If the previous instruction was marked for elimination, remove it now.
176 if (ToErase) {
177 ToErase->eraseFromParent();
178 ToErase = nullptr;
179 }
Yonghong Song60fed1f2018-02-23 23:49:32 +0000180
Yonghong Songc88bcde2018-03-13 06:47:03 +0000181 // Eliminate the 32-bit to 64-bit zero extension sequence when possible.
182 //
183 // MOV_32_64 rB, wA
184 // SLL_ri rB, rB, 32
185 // SRL_ri rB, rB, 32
186 if (MI.getOpcode() == BPF::SRL_ri &&
187 MI.getOperand(2).getImm() == 32) {
Daniel Sanders0c476112019-08-15 19:22:08 +0000188 Register DstReg = MI.getOperand(0).getReg();
189 Register ShfReg = MI.getOperand(1).getReg();
Yonghong Songc88bcde2018-03-13 06:47:03 +0000190 MachineInstr *SllMI = MRI->getVRegDef(ShfReg);
191
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000192 LLVM_DEBUG(dbgs() << "Starting SRL found:");
193 LLVM_DEBUG(MI.dump());
Yonghong Song82bf8bc2018-03-13 06:47:07 +0000194
Yonghong Songc88bcde2018-03-13 06:47:03 +0000195 if (!SllMI ||
196 SllMI->isPHI() ||
197 SllMI->getOpcode() != BPF::SLL_ri ||
198 SllMI->getOperand(2).getImm() != 32)
199 continue;
200
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000201 LLVM_DEBUG(dbgs() << " SLL found:");
202 LLVM_DEBUG(SllMI->dump());
Yonghong Song82bf8bc2018-03-13 06:47:07 +0000203
Yonghong Songc88bcde2018-03-13 06:47:03 +0000204 MachineInstr *MovMI = MRI->getVRegDef(SllMI->getOperand(1).getReg());
205 if (!MovMI ||
206 MovMI->isPHI() ||
207 MovMI->getOpcode() != BPF::MOV_32_64)
208 continue;
209
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000210 LLVM_DEBUG(dbgs() << " Type cast Mov found:");
211 LLVM_DEBUG(MovMI->dump());
Yonghong Song82bf8bc2018-03-13 06:47:07 +0000212
Daniel Sanders0c476112019-08-15 19:22:08 +0000213 Register SubReg = MovMI->getOperand(1).getReg();
Yonghong Song82bf8bc2018-03-13 06:47:07 +0000214 if (!isMovFrom32Def(MovMI)) {
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000215 LLVM_DEBUG(dbgs()
216 << " One ZExt elim sequence failed qualifying elim.\n");
Yonghong Songc88bcde2018-03-13 06:47:03 +0000217 continue;
Yonghong Song82bf8bc2018-03-13 06:47:07 +0000218 }
Yonghong Songc88bcde2018-03-13 06:47:03 +0000219
Yonghong Songc88bcde2018-03-13 06:47:03 +0000220 BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(BPF::SUBREG_TO_REG), DstReg)
221 .addImm(0).addReg(SubReg).addImm(BPF::sub_32);
222
223 SllMI->eraseFromParent();
224 MovMI->eraseFromParent();
225 // MI is the right shift, we can't erase it in it's own iteration.
226 // Mark it to ToErase, and erase in the next iteration.
227 ToErase = &MI;
228 ZExtElemNum++;
229 Eliminated = true;
Yonghong Song60fed1f2018-02-23 23:49:32 +0000230 }
231 }
232 }
233
234 return Eliminated;
235}
236
237} // end default namespace
238
Yonghong Songe91802f2018-03-13 06:47:06 +0000239INITIALIZE_PASS(BPFMIPeephole, DEBUG_TYPE,
Jiong Wangec518512019-10-16 15:27:59 +0000240 "BPF MachineSSA Peephole Optimization For ZEXT Eliminate",
241 false, false)
Yonghong Song60fed1f2018-02-23 23:49:32 +0000242
243char BPFMIPeephole::ID = 0;
244FunctionPass* llvm::createBPFMIPeepholePass() { return new BPFMIPeephole(); }
Yonghong Songe91802f2018-03-13 06:47:06 +0000245
246STATISTIC(RedundantMovElemNum, "Number of redundant moves eliminated");
247
248namespace {
249
250struct BPFMIPreEmitPeephole : public MachineFunctionPass {
251
252 static char ID;
253 MachineFunction *MF;
254 const TargetRegisterInfo *TRI;
255
256 BPFMIPreEmitPeephole() : MachineFunctionPass(ID) {
257 initializeBPFMIPreEmitPeepholePass(*PassRegistry::getPassRegistry());
258 }
259
260private:
261 // Initialize class variables.
262 void initialize(MachineFunction &MFParm);
263
264 bool eliminateRedundantMov(void);
265
266public:
267
268 // Main entry point for this pass.
269 bool runOnMachineFunction(MachineFunction &MF) override {
270 if (skipFunction(MF.getFunction()))
271 return false;
272
273 initialize(MF);
274
275 return eliminateRedundantMov();
276 }
277};
278
279// Initialize class variables.
280void BPFMIPreEmitPeephole::initialize(MachineFunction &MFParm) {
281 MF = &MFParm;
282 TRI = MF->getSubtarget<BPFSubtarget>().getRegisterInfo();
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000283 LLVM_DEBUG(dbgs() << "*** BPF PreEmit peephole pass ***\n\n");
Yonghong Songe91802f2018-03-13 06:47:06 +0000284}
285
286bool BPFMIPreEmitPeephole::eliminateRedundantMov(void) {
287 MachineInstr* ToErase = nullptr;
288 bool Eliminated = false;
289
290 for (MachineBasicBlock &MBB : *MF) {
291 for (MachineInstr &MI : MBB) {
292 // If the previous instruction was marked for elimination, remove it now.
293 if (ToErase) {
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000294 LLVM_DEBUG(dbgs() << " Redundant Mov Eliminated:");
295 LLVM_DEBUG(ToErase->dump());
Yonghong Songe91802f2018-03-13 06:47:06 +0000296 ToErase->eraseFromParent();
297 ToErase = nullptr;
298 }
299
300 // Eliminate identical move:
301 //
302 // MOV rA, rA
303 //
304 // This is particularly possible to happen when sub-register support
305 // enabled. The special type cast insn MOV_32_64 involves different
306 // register class on src (i32) and dst (i64), RA could generate useless
307 // instruction due to this.
Jiong Wangec518512019-10-16 15:27:59 +0000308 unsigned Opcode = MI.getOpcode();
309 if (Opcode == BPF::MOV_32_64 ||
310 Opcode == BPF::MOV_rr || Opcode == BPF::MOV_rr_32) {
Daniel Sanders0c476112019-08-15 19:22:08 +0000311 Register dst = MI.getOperand(0).getReg();
Daniel Sanders0c476112019-08-15 19:22:08 +0000312 Register src = MI.getOperand(1).getReg();
Yonghong Songe91802f2018-03-13 06:47:06 +0000313
Jiong Wangec518512019-10-16 15:27:59 +0000314 if (Opcode == BPF::MOV_32_64)
315 dst = TRI->getSubReg(dst, BPF::sub_32);
316
317 if (dst != src)
Yonghong Songe91802f2018-03-13 06:47:06 +0000318 continue;
319
320 ToErase = &MI;
321 RedundantMovElemNum++;
322 Eliminated = true;
323 }
324 }
325 }
326
327 return Eliminated;
328}
329
330} // end default namespace
331
332INITIALIZE_PASS(BPFMIPreEmitPeephole, "bpf-mi-pemit-peephole",
333 "BPF PreEmit Peephole Optimization", false, false)
334
335char BPFMIPreEmitPeephole::ID = 0;
336FunctionPass* llvm::createBPFMIPreEmitPeepholePass()
337{
338 return new BPFMIPreEmitPeephole();
339}
Jiong Wangec518512019-10-16 15:27:59 +0000340
341STATISTIC(TruncElemNum, "Number of truncation eliminated");
342
343namespace {
344
345struct BPFMIPeepholeTruncElim : public MachineFunctionPass {
346
347 static char ID;
348 const BPFInstrInfo *TII;
349 MachineFunction *MF;
350 MachineRegisterInfo *MRI;
351
352 BPFMIPeepholeTruncElim() : MachineFunctionPass(ID) {
353 initializeBPFMIPeepholeTruncElimPass(*PassRegistry::getPassRegistry());
354 }
355
356private:
357 // Initialize class variables.
358 void initialize(MachineFunction &MFParm);
359
360 bool eliminateTruncSeq(void);
361
362public:
363
364 // Main entry point for this pass.
365 bool runOnMachineFunction(MachineFunction &MF) override {
366 if (skipFunction(MF.getFunction()))
367 return false;
368
369 initialize(MF);
370
371 return eliminateTruncSeq();
372 }
373};
374
375static bool TruncSizeCompatible(int TruncSize, unsigned opcode)
376{
377 if (TruncSize == 1)
378 return opcode == BPF::LDB || opcode == BPF::LDB32;
379
380 if (TruncSize == 2)
381 return opcode == BPF::LDH || opcode == BPF::LDH32;
382
383 if (TruncSize == 4)
384 return opcode == BPF::LDW || opcode == BPF::LDW32;
385
386 return false;
387}
388
389// Initialize class variables.
390void BPFMIPeepholeTruncElim::initialize(MachineFunction &MFParm) {
391 MF = &MFParm;
392 MRI = &MF->getRegInfo();
393 TII = MF->getSubtarget<BPFSubtarget>().getInstrInfo();
394 LLVM_DEBUG(dbgs() << "*** BPF MachineSSA TRUNC Elim peephole pass ***\n\n");
395}
396
397// Reg truncating is often the result of 8/16/32bit->64bit or
398// 8/16bit->32bit conversion. If the reg value is loaded with
399// masked byte width, the AND operation can be removed since
400// BPF LOAD already has zero extension.
401//
402// This also solved a correctness issue.
403// In BPF socket-related program, e.g., __sk_buff->{data, data_end}
404// are 32-bit registers, but later on, kernel verifier will rewrite
405// it with 64-bit value. Therefore, truncating the value after the
406// load will result in incorrect code.
407bool BPFMIPeepholeTruncElim::eliminateTruncSeq(void) {
408 MachineInstr* ToErase = nullptr;
409 bool Eliminated = false;
410
411 for (MachineBasicBlock &MBB : *MF) {
412 for (MachineInstr &MI : MBB) {
413 // The second insn to remove if the eliminate candidate is a pair.
414 MachineInstr *MI2 = nullptr;
415 Register DstReg, SrcReg;
416 MachineInstr *DefMI;
417 int TruncSize = -1;
418
419 // If the previous instruction was marked for elimination, remove it now.
420 if (ToErase) {
421 ToErase->eraseFromParent();
422 ToErase = nullptr;
423 }
424
425 // AND A, 0xFFFFFFFF will be turned into SLL/SRL pair due to immediate
426 // for BPF ANDI is i32, and this case only happens on ALU64.
427 if (MI.getOpcode() == BPF::SRL_ri &&
428 MI.getOperand(2).getImm() == 32) {
429 SrcReg = MI.getOperand(1).getReg();
430 MI2 = MRI->getVRegDef(SrcReg);
431 DstReg = MI.getOperand(0).getReg();
432
433 if (!MI2 ||
434 MI2->getOpcode() != BPF::SLL_ri ||
435 MI2->getOperand(2).getImm() != 32)
436 continue;
437
438 // Update SrcReg.
439 SrcReg = MI2->getOperand(1).getReg();
440 DefMI = MRI->getVRegDef(SrcReg);
441 if (DefMI)
442 TruncSize = 4;
443 } else if (MI.getOpcode() == BPF::AND_ri ||
444 MI.getOpcode() == BPF::AND_ri_32) {
445 SrcReg = MI.getOperand(1).getReg();
446 DstReg = MI.getOperand(0).getReg();
447 DefMI = MRI->getVRegDef(SrcReg);
448
449 if (!DefMI)
450 continue;
451
452 int64_t imm = MI.getOperand(2).getImm();
453 if (imm == 0xff)
454 TruncSize = 1;
455 else if (imm == 0xffff)
456 TruncSize = 2;
457 }
458
459 if (TruncSize == -1)
460 continue;
461
462 // The definition is PHI node, check all inputs.
463 if (DefMI->isPHI()) {
464 bool CheckFail = false;
465
466 for (unsigned i = 1, e = DefMI->getNumOperands(); i < e; i += 2) {
467 MachineOperand &opnd = DefMI->getOperand(i);
468 if (!opnd.isReg()) {
469 CheckFail = true;
470 break;
471 }
472
473 MachineInstr *PhiDef = MRI->getVRegDef(opnd.getReg());
474 if (!PhiDef || PhiDef->isPHI() ||
475 !TruncSizeCompatible(TruncSize, PhiDef->getOpcode())) {
476 CheckFail = true;
477 break;
478 }
479 }
480
481 if (CheckFail)
482 continue;
483 } else if (!TruncSizeCompatible(TruncSize, DefMI->getOpcode())) {
484 continue;
485 }
486
487 BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(BPF::MOV_rr), DstReg)
488 .addReg(SrcReg);
489
490 if (MI2)
491 MI2->eraseFromParent();
492
493 // Mark it to ToErase, and erase in the next iteration.
494 ToErase = &MI;
495 TruncElemNum++;
496 Eliminated = true;
497 }
498 }
499
500 return Eliminated;
501}
502
503} // end default namespace
504
505INITIALIZE_PASS(BPFMIPeepholeTruncElim, "bpf-mi-trunc-elim",
506 "BPF MachineSSA Peephole Optimization For TRUNC Eliminate",
507 false, false)
508
509char BPFMIPeepholeTruncElim::ID = 0;
510FunctionPass* llvm::createBPFMIPeepholeTruncElimPass()
511{
512 return new BPFMIPeepholeTruncElim();
513}