LLVM 23.0.0git
BPFMIPeephole.cpp
Go to the documentation of this file.
1//===-------------- BPFMIPeephole.cpp - MI Peephole Cleanups -------------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8//
9// This pass performs peephole optimizations to cleanup ugly code sequences at
10// MachineInstruction layer.
11//
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
17// implicitly.
18//
19// - One post-RA PreEmit pass to do final cleanup on some redundant
20// instructions generated due to bad RA on subregister.
21//===----------------------------------------------------------------------===//
22
23#include "BPF.h"
24#include "BPFInstrInfo.h"
25#include "BPFTargetMachine.h"
26#include "llvm/ADT/Statistic.h"
33#include "llvm/Support/Debug.h"
34#include <set>
35
36using namespace llvm;
37
38#define DEBUG_TYPE "bpf-mi-zext-elim"
39
40static cl::opt<int> GotolAbsLowBound("gotol-abs-low-bound", cl::Hidden,
41 cl::init(INT16_MAX >> 1), cl::desc("Specify gotol lower bound"));
42
43STATISTIC(ZExtElemNum, "Number of zero extension shifts eliminated");
44
45namespace {
46
47struct BPFMIPeephole : public MachineFunctionPass {
48
49 static char ID;
50 const BPFInstrInfo *TII;
53
54 BPFMIPeephole() : MachineFunctionPass(ID) {}
55
56private:
57 // Initialize class variables.
58 void initialize(MachineFunction &MFParm);
59
60 bool isCopyFrom32Def(MachineInstr *CopyMI);
61 bool isInsnFrom32Def(MachineInstr *DefInsn);
62 bool isPhiFrom32Def(MachineInstr *MovMI);
63 bool isMovFrom32Def(MachineInstr *MovMI);
64 bool eliminateZExtSeq();
65 bool eliminateZExt();
66
67 std::set<MachineInstr *> PhiInsns;
68
69public:
70
71 // Main entry point for this pass.
72 bool runOnMachineFunction(MachineFunction &MF) override {
73 if (skipFunction(MF.getFunction()))
74 return false;
75
76 initialize(MF);
77
78 // First try to eliminate (zext, lshift, rshift) and then
79 // try to eliminate zext.
80 bool ZExtSeqExist, ZExtExist;
81 ZExtSeqExist = eliminateZExtSeq();
82 ZExtExist = eliminateZExt();
83 return ZExtSeqExist || ZExtExist;
84 }
85};
86
87// Initialize class variables.
88void BPFMIPeephole::initialize(MachineFunction &MFParm) {
89 MF = &MFParm;
90 MRI = &MF->getRegInfo();
91 TII = MF->getSubtarget<BPFSubtarget>().getInstrInfo();
92 LLVM_DEBUG(dbgs() << "*** BPF MachineSSA ZEXT Elim peephole pass ***\n\n");
93}
94
95bool BPFMIPeephole::isCopyFrom32Def(MachineInstr *CopyMI)
96{
97 MachineOperand &opnd = CopyMI->getOperand(1);
98
99 // Return false if getting value from a 32bit physical register.
100 // Most likely, this physical register is aliased to
101 // function call return value or current function parameters.
102 Register Reg = opnd.getReg();
103 if (!Reg.isVirtual())
104 return false;
105
106 if (MRI->getRegClass(Reg) == &BPF::GPRRegClass)
107 return false;
108
109 MachineInstr *DefInsn = MRI->getVRegDef(Reg);
110 if (!isInsnFrom32Def(DefInsn))
111 return false;
112
113 return true;
114}
115
116bool BPFMIPeephole::isPhiFrom32Def(MachineInstr *PhiMI)
117{
118 for (unsigned i = 1, e = PhiMI->getNumOperands(); i < e; i += 2) {
119 MachineOperand &opnd = PhiMI->getOperand(i);
120
121 MachineInstr *PhiDef = MRI->getVRegDef(opnd.getReg());
122 if (!PhiDef)
123 return false;
124 if (PhiDef->isPHI()) {
125 if (!PhiInsns.insert(PhiDef).second)
126 return false;
127 if (!isPhiFrom32Def(PhiDef))
128 return false;
129 }
130 if (PhiDef->getOpcode() == BPF::COPY && !isCopyFrom32Def(PhiDef))
131 return false;
132 }
133
134 return true;
135}
136
137// The \p DefInsn instruction defines a virtual register.
138bool BPFMIPeephole::isInsnFrom32Def(MachineInstr *DefInsn)
139{
140 if (!DefInsn)
141 return false;
142
143 if (DefInsn->isPHI()) {
144 if (!PhiInsns.insert(DefInsn).second)
145 return false;
146 if (!isPhiFrom32Def(DefInsn))
147 return false;
148 } else if (DefInsn->getOpcode() == BPF::COPY) {
149 if (!isCopyFrom32Def(DefInsn))
150 return false;
151 }
152
153 return true;
154}
155
156bool BPFMIPeephole::isMovFrom32Def(MachineInstr *MovMI)
157{
158 const MachineOperand &Src = MovMI->getOperand(1);
159 if (Src.getSubReg())
160 return false;
161
162 MachineInstr *DefInsn = MRI->getVRegDef(Src.getReg());
163
164 LLVM_DEBUG(dbgs() << " Def of Mov Src:");
165 LLVM_DEBUG(DefInsn->dump());
166
167 PhiInsns.clear();
168 if (!isInsnFrom32Def(DefInsn))
169 return false;
170
171 LLVM_DEBUG(dbgs() << " One ZExt elim sequence identified.\n");
172
173 return true;
174}
175
176bool BPFMIPeephole::eliminateZExtSeq() {
177 MachineInstr* ToErase = nullptr;
178 bool Eliminated = false;
179
180 for (MachineBasicBlock &MBB : *MF) {
181 for (MachineInstr &MI : MBB) {
182 // If the previous instruction was marked for elimination, remove it now.
183 if (ToErase) {
184 ToErase->eraseFromParent();
185 ToErase = nullptr;
186 }
187
188 // Eliminate the 32-bit to 64-bit zero extension sequence when possible.
189 //
190 // MOV_32_64 rB, wA
191 // SLL_ri rB, rB, 32
192 // SRL_ri rB, rB, 32
193 if (MI.getOpcode() == BPF::SRL_ri &&
194 MI.getOperand(2).getImm() == 32) {
195 Register DstReg = MI.getOperand(0).getReg();
196 Register ShfReg = MI.getOperand(1).getReg();
197 MachineInstr *SllMI = MRI->getVRegDef(ShfReg);
198
199 LLVM_DEBUG(dbgs() << "Starting SRL found:");
200 LLVM_DEBUG(MI.dump());
201
202 if (!SllMI ||
203 SllMI->isPHI() ||
204 SllMI->getOpcode() != BPF::SLL_ri ||
205 SllMI->getOperand(2).getImm() != 32)
206 continue;
207
208 LLVM_DEBUG(dbgs() << " SLL found:");
209 LLVM_DEBUG(SllMI->dump());
210
211 MachineInstr *MovMI = MRI->getVRegDef(SllMI->getOperand(1).getReg());
212 if (!MovMI ||
213 MovMI->isPHI() ||
214 MovMI->getOpcode() != BPF::MOV_32_64)
215 continue;
216
217 LLVM_DEBUG(dbgs() << " Type cast Mov found:");
218 LLVM_DEBUG(MovMI->dump());
219
220 Register SubReg = MovMI->getOperand(1).getReg();
221 if (!isMovFrom32Def(MovMI)) {
223 << " One ZExt elim sequence failed qualifying elim.\n");
224 continue;
225 }
226
227 BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(BPF::SUBREG_TO_REG), DstReg)
228 .addReg(SubReg)
229 .addImm(BPF::sub_32);
230
231 SllMI->eraseFromParent();
232 MovMI->eraseFromParent();
233 // MI is the right shift, we can't erase it in it's own iteration.
234 // Mark it to ToErase, and erase in the next iteration.
235 ToErase = &MI;
236 ZExtElemNum++;
237 Eliminated = true;
238 }
239 }
240 }
241
242 return Eliminated;
243}
244
245bool BPFMIPeephole::eliminateZExt() {
246 MachineInstr* ToErase = nullptr;
247 bool Eliminated = false;
248
249 for (MachineBasicBlock &MBB : *MF) {
250 for (MachineInstr &MI : MBB) {
251 // If the previous instruction was marked for elimination, remove it now.
252 if (ToErase) {
253 ToErase->eraseFromParent();
254 ToErase = nullptr;
255 }
256
257 if (MI.getOpcode() != BPF::MOV_32_64)
258 continue;
259
260 // Eliminate MOV_32_64 if possible.
261 // MOV_32_64 rA, wB
262 //
263 // If wB has been zero extended, replace it with a SUBREG_TO_REG.
264 // This is to workaround BPF programs where pkt->{data, data_end}
265 // is encoded as u32, but actually the verifier populates them
266 // as 64bit pointer. The MOV_32_64 will zero out the top 32 bits.
267 LLVM_DEBUG(dbgs() << "Candidate MOV_32_64 instruction:");
268 LLVM_DEBUG(MI.dump());
269
270 if (!isMovFrom32Def(&MI))
271 continue;
272
273 LLVM_DEBUG(dbgs() << "Removing the MOV_32_64 instruction\n");
274
275 Register dst = MI.getOperand(0).getReg();
276 Register src = MI.getOperand(1).getReg();
277
278 // Build a SUBREG_TO_REG instruction.
279 BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(BPF::SUBREG_TO_REG), dst)
280 .addReg(src)
281 .addImm(BPF::sub_32);
282
283 ToErase = &MI;
284 Eliminated = true;
285 }
286 }
287
288 return Eliminated;
289}
290
291} // end default namespace
292
293INITIALIZE_PASS(BPFMIPeephole, DEBUG_TYPE,
294 "BPF MachineSSA Peephole Optimization For ZEXT Eliminate",
295 false, false)
296
297char BPFMIPeephole::ID = 0;
298FunctionPass* llvm::createBPFMIPeepholePass() { return new BPFMIPeephole(); }
299
300STATISTIC(RedundantMovElemNum, "Number of redundant moves eliminated");
301
302namespace {
303
304struct BPFMIPreEmitPeephole : public MachineFunctionPass {
305
306 static char ID;
307 MachineFunction *MF;
308 const TargetRegisterInfo *TRI;
309 const BPFInstrInfo *TII;
310 bool SupportGotol;
311
312 BPFMIPreEmitPeephole() : MachineFunctionPass(ID) {}
313
314private:
315 // Initialize class variables.
316 void initialize(MachineFunction &MFParm);
317
318 bool in16BitRange(int Num);
319 bool eliminateRedundantMov();
320 bool adjustBranch();
321 bool insertMissingCallerSavedSpills();
322 bool removeMayGotoZero();
323 bool addExitAfterUnreachable();
324 bool expandStackArgPseudos();
325
326public:
327
328 // Main entry point for this pass.
329 bool runOnMachineFunction(MachineFunction &MF) override {
330 initialize(MF);
331
332 bool Changed = expandStackArgPseudos();
333 if (skipFunction(MF.getFunction()))
334 return Changed;
335
336 Changed |= eliminateRedundantMov();
337 if (SupportGotol)
338 Changed |= adjustBranch();
339 Changed |= insertMissingCallerSavedSpills();
340 Changed |= removeMayGotoZero();
341 Changed |= addExitAfterUnreachable();
342 return Changed;
343 }
344};
345
346// Initialize class variables.
347void BPFMIPreEmitPeephole::initialize(MachineFunction &MFParm) {
348 MF = &MFParm;
349 TII = MF->getSubtarget<BPFSubtarget>().getInstrInfo();
350 TRI = MF->getSubtarget<BPFSubtarget>().getRegisterInfo();
351 SupportGotol = MF->getSubtarget<BPFSubtarget>().hasGotol();
352 LLVM_DEBUG(dbgs() << "*** BPF PreEmit peephole pass ***\n\n");
353}
354
355bool BPFMIPreEmitPeephole::eliminateRedundantMov() {
356 MachineInstr* ToErase = nullptr;
357 bool Eliminated = false;
358
359 for (MachineBasicBlock &MBB : *MF) {
360 for (MachineInstr &MI : MBB) {
361 // If the previous instruction was marked for elimination, remove it now.
362 if (ToErase) {
363 LLVM_DEBUG(dbgs() << " Redundant Mov Eliminated:");
364 LLVM_DEBUG(ToErase->dump());
365 ToErase->eraseFromParent();
366 ToErase = nullptr;
367 }
368
369 // Eliminate identical move:
370 //
371 // MOV rA, rA
372 //
373 // Note that we cannot remove
374 // MOV_32_64 rA, wA
375 // MOV_rr_32 wA, wA
376 // as these two instructions having side effects, zeroing out
377 // top 32 bits of rA.
378 unsigned Opcode = MI.getOpcode();
379 if (Opcode == BPF::MOV_rr) {
380 Register dst = MI.getOperand(0).getReg();
381 Register src = MI.getOperand(1).getReg();
382
383 if (dst != src)
384 continue;
385
386 ToErase = &MI;
387 RedundantMovElemNum++;
388 Eliminated = true;
389 }
390 }
391 }
392
393 return Eliminated;
394}
395
396bool BPFMIPreEmitPeephole::in16BitRange(int Num) {
397 // Well, the cut-off is not precisely at 16bit range since
398 // new codes are added during the transformation. So let us
399 // a little bit conservative.
400 return Num >= -GotolAbsLowBound && Num <= GotolAbsLowBound;
401}
402
403// Before cpu=v4, only 16bit branch target offset (-0x8000 to 0x7fff)
404// is supported for both unconditional (JMP) and condition (JEQ, JSGT,
405// etc.) branches. In certain cases, e.g., full unrolling, the branch
406// target offset might exceed 16bit range. If this happens, the llvm
407// will generate incorrect code as the offset is truncated to 16bit.
408//
409// To fix this rare case, a new insn JMPL is introduced. This new
410// insn supports supports 32bit branch target offset. The compiler
411// does not use this insn during insn selection. Rather, BPF backend
412// will estimate the branch target offset and do JMP -> JMPL and
413// JEQ -> JEQ + JMPL conversion if the estimated branch target offset
414// is beyond 16bit.
415bool BPFMIPreEmitPeephole::adjustBranch() {
416 bool Changed = false;
417 int CurrNumInsns = 0;
418 DenseMap<MachineBasicBlock *, int> SoFarNumInsns;
419 DenseMap<MachineBasicBlock *, MachineBasicBlock *> FollowThroughBB;
420 std::vector<MachineBasicBlock *> MBBs;
421
422 MachineBasicBlock *PrevBB = nullptr;
423 for (MachineBasicBlock &MBB : *MF) {
424 // MBB.size() is the number of insns in this basic block, including some
425 // debug info, e.g., DEBUG_VALUE, so we may over-count a little bit.
426 // Typically we have way more normal insns than DEBUG_VALUE insns.
427 // Also, if we indeed need to convert conditional branch like JEQ to
428 // JEQ + JMPL, we actually introduced some new insns like below.
429 CurrNumInsns += (int)MBB.size();
430 SoFarNumInsns[&MBB] = CurrNumInsns;
431 if (PrevBB != nullptr)
432 FollowThroughBB[PrevBB] = &MBB;
433 PrevBB = &MBB;
434 // A list of original BBs to make later traveral easier.
435 MBBs.push_back(&MBB);
436 }
437 FollowThroughBB[PrevBB] = nullptr;
438
439 for (unsigned i = 0; i < MBBs.size(); i++) {
440 // We have four cases here:
441 // (1). no terminator, simple follow through.
442 // (2). jmp to another bb.
443 // (3). conditional jmp to another bb or follow through.
444 // (4). conditional jmp followed by an unconditional jmp.
445 MachineInstr *CondJmp = nullptr, *UncondJmp = nullptr;
446
447 MachineBasicBlock *MBB = MBBs[i];
448 for (MachineInstr &Term : MBB->terminators()) {
449 if (Term.isConditionalBranch()) {
450 assert(CondJmp == nullptr);
451 CondJmp = &Term;
452 } else if (Term.isUnconditionalBranch()) {
453 assert(UncondJmp == nullptr);
454 UncondJmp = &Term;
455 }
456 }
457
458 // (1). no terminator, simple follow through.
459 if (!CondJmp && !UncondJmp)
460 continue;
461
462 MachineBasicBlock *CondTargetBB, *JmpBB;
463 CurrNumInsns = SoFarNumInsns[MBB];
464
465 // (2). jmp to another bb.
466 if (!CondJmp && UncondJmp) {
467 JmpBB = UncondJmp->getOperand(0).getMBB();
468 if (in16BitRange(SoFarNumInsns[JmpBB] - JmpBB->size() - CurrNumInsns))
469 continue;
470
471 // replace this insn as a JMPL.
472 BuildMI(MBB, UncondJmp->getDebugLoc(), TII->get(BPF::JMPL)).addMBB(JmpBB);
473 UncondJmp->eraseFromParent();
474 Changed = true;
475 continue;
476 }
477
478 const BasicBlock *TermBB = MBB->getBasicBlock();
479 int Dist;
480
481 // (3). conditional jmp to another bb or follow through.
482 if (!UncondJmp) {
483 CondTargetBB = CondJmp->getOperand(2).getMBB();
484 MachineBasicBlock *FollowBB = FollowThroughBB[MBB];
485 Dist = SoFarNumInsns[CondTargetBB] - CondTargetBB->size() - CurrNumInsns;
486 if (in16BitRange(Dist))
487 continue;
488
489 // We have
490 // B2: ...
491 // if (cond) goto B5
492 // B3: ...
493 // where B2 -> B5 is beyond 16bit range.
494 //
495 // We do not have 32bit cond jmp insn. So we try to do
496 // the following.
497 // B2: ...
498 // if (cond) goto New_B1
499 // New_B0 goto B3
500 // New_B1: gotol B5
501 // B3: ...
502 // Basically two new basic blocks are created.
503 MachineBasicBlock *New_B0 = MF->CreateMachineBasicBlock(TermBB);
504 MachineBasicBlock *New_B1 = MF->CreateMachineBasicBlock(TermBB);
505
506 // Insert New_B0 and New_B1 into function block list.
508 MF->insert(MBB_I, New_B0);
509 MF->insert(MBB_I, New_B1);
510
511 // replace B2 cond jump
512 if (CondJmp->getOperand(1).isReg())
513 BuildMI(*MBB, MachineBasicBlock::iterator(*CondJmp), CondJmp->getDebugLoc(), TII->get(CondJmp->getOpcode()))
514 .addReg(CondJmp->getOperand(0).getReg())
515 .addReg(CondJmp->getOperand(1).getReg())
516 .addMBB(New_B1);
517 else
518 BuildMI(*MBB, MachineBasicBlock::iterator(*CondJmp), CondJmp->getDebugLoc(), TII->get(CondJmp->getOpcode()))
519 .addReg(CondJmp->getOperand(0).getReg())
520 .addImm(CondJmp->getOperand(1).getImm())
521 .addMBB(New_B1);
522
523 // it is possible that CondTargetBB and FollowBB are the same. But the
524 // above Dist checking should already filtered this case.
525 MBB->removeSuccessor(CondTargetBB);
526 MBB->removeSuccessor(FollowBB);
527 MBB->addSuccessor(New_B0);
528 MBB->addSuccessor(New_B1);
529
530 // Populate insns in New_B0 and New_B1.
531 BuildMI(New_B0, CondJmp->getDebugLoc(), TII->get(BPF::JMP)).addMBB(FollowBB);
532 BuildMI(New_B1, CondJmp->getDebugLoc(), TII->get(BPF::JMPL))
533 .addMBB(CondTargetBB);
534
535 New_B0->addSuccessor(FollowBB);
536 New_B1->addSuccessor(CondTargetBB);
537 CondJmp->eraseFromParent();
538 Changed = true;
539 continue;
540 }
541
542 // (4). conditional jmp followed by an unconditional jmp.
543 CondTargetBB = CondJmp->getOperand(2).getMBB();
544 JmpBB = UncondJmp->getOperand(0).getMBB();
545
546 // We have
547 // B2: ...
548 // if (cond) goto B5
549 // JMP B7
550 // B3: ...
551 //
552 // If only B2->B5 is out of 16bit range, we can do
553 // B2: ...
554 // if (cond) goto new_B
555 // JMP B7
556 // New_B: gotol B5
557 // B3: ...
558 //
559 // If only 'JMP B7' is out of 16bit range, we can replace
560 // 'JMP B7' with 'JMPL B7'.
561 //
562 // If both B2->B5 and 'JMP B7' is out of range, just do
563 // both the above transformations.
564 Dist = SoFarNumInsns[CondTargetBB] - CondTargetBB->size() - CurrNumInsns;
565 if (!in16BitRange(Dist)) {
566 MachineBasicBlock *New_B = MF->CreateMachineBasicBlock(TermBB);
567
568 // Insert New_B0 into function block list.
569 MF->insert(++MBB->getIterator(), New_B);
570
571 // replace B2 cond jump
572 if (CondJmp->getOperand(1).isReg())
573 BuildMI(*MBB, MachineBasicBlock::iterator(*CondJmp), CondJmp->getDebugLoc(), TII->get(CondJmp->getOpcode()))
574 .addReg(CondJmp->getOperand(0).getReg())
575 .addReg(CondJmp->getOperand(1).getReg())
576 .addMBB(New_B);
577 else
578 BuildMI(*MBB, MachineBasicBlock::iterator(*CondJmp), CondJmp->getDebugLoc(), TII->get(CondJmp->getOpcode()))
579 .addReg(CondJmp->getOperand(0).getReg())
580 .addImm(CondJmp->getOperand(1).getImm())
581 .addMBB(New_B);
582
583 if (CondTargetBB != JmpBB)
584 MBB->removeSuccessor(CondTargetBB);
585 MBB->addSuccessor(New_B);
586
587 // Populate insn in New_B.
588 BuildMI(New_B, CondJmp->getDebugLoc(), TII->get(BPF::JMPL)).addMBB(CondTargetBB);
589
590 New_B->addSuccessor(CondTargetBB);
591 CondJmp->eraseFromParent();
592 Changed = true;
593 }
594
595 if (!in16BitRange(SoFarNumInsns[JmpBB] - CurrNumInsns)) {
596 BuildMI(MBB, UncondJmp->getDebugLoc(), TII->get(BPF::JMPL)).addMBB(JmpBB);
597 UncondJmp->eraseFromParent();
598 Changed = true;
599 }
600 }
601
602 return Changed;
603}
604
605static const unsigned CallerSavedRegs[] = {BPF::R0, BPF::R1, BPF::R2,
606 BPF::R3, BPF::R4, BPF::R5};
607
608struct BPFFastCall {
609 MachineInstr *MI;
610 unsigned LiveCallerSavedRegs;
611};
612
613static void collectBPFFastCalls(const TargetRegisterInfo *TRI,
614 LivePhysRegs &LiveRegs, MachineBasicBlock &BB,
615 SmallVectorImpl<BPFFastCall> &Calls) {
616 LiveRegs.init(*TRI);
617 LiveRegs.addLiveOuts(BB);
618 Calls.clear();
619 for (MachineInstr &MI : llvm::reverse(BB)) {
620 if (MI.isCall()) {
621 unsigned LiveCallerSavedRegs = 0;
622 for (MCRegister R : CallerSavedRegs) {
623 bool DoSpillFill = false;
624 for (MCPhysReg SR : TRI->subregs(R))
625 DoSpillFill |= !MI.definesRegister(SR, TRI) && LiveRegs.contains(SR);
626 if (!DoSpillFill)
627 continue;
628 LiveCallerSavedRegs |= 1 << R;
629 }
630 if (LiveCallerSavedRegs)
631 Calls.push_back({&MI, LiveCallerSavedRegs});
632 }
633 LiveRegs.stepBackward(MI);
634 }
635}
636
637static int64_t computeMinFixedObjOffset(MachineFrameInfo &MFI,
638 unsigned SlotSize) {
639 int64_t MinFixedObjOffset = 0;
640 // Same logic as in X86FrameLowering::adjustFrameForMsvcCxxEh()
641 for (int I = MFI.getObjectIndexBegin(); I < MFI.getObjectIndexEnd(); ++I) {
642 if (MFI.isDeadObjectIndex(I))
643 continue;
644 MinFixedObjOffset = std::min(MinFixedObjOffset, MFI.getObjectOffset(I));
645 }
646 MinFixedObjOffset -=
647 (SlotSize + MinFixedObjOffset % SlotSize) & (SlotSize - 1);
648 return MinFixedObjOffset;
649}
650
651bool BPFMIPreEmitPeephole::insertMissingCallerSavedSpills() {
652 MachineFrameInfo &MFI = MF->getFrameInfo();
654 LivePhysRegs LiveRegs;
655 const unsigned SlotSize = 8;
656 int64_t MinFixedObjOffset = computeMinFixedObjOffset(MFI, SlotSize);
657 bool Changed = false;
658 for (MachineBasicBlock &BB : *MF) {
659 collectBPFFastCalls(TRI, LiveRegs, BB, Calls);
660 Changed |= !Calls.empty();
661 for (BPFFastCall &Call : Calls) {
662 int64_t CurOffset = MinFixedObjOffset;
663 for (MCRegister Reg : CallerSavedRegs) {
664 if (((1 << Reg) & Call.LiveCallerSavedRegs) == 0)
665 continue;
666 // Allocate stack object
667 CurOffset -= SlotSize;
668 MFI.CreateFixedSpillStackObject(SlotSize, CurOffset);
669 // Generate spill
670 BuildMI(BB, Call.MI->getIterator(), Call.MI->getDebugLoc(),
671 TII->get(BPF::STD))
672 .addReg(Reg, RegState::Kill)
673 .addReg(BPF::R10)
674 .addImm(CurOffset);
675 // Generate fill
676 BuildMI(BB, ++Call.MI->getIterator(), Call.MI->getDebugLoc(),
677 TII->get(BPF::LDD))
678 .addReg(Reg, RegState::Define)
679 .addReg(BPF::R10)
680 .addImm(CurOffset);
681 }
682 }
683 }
684 return Changed;
685}
686
687bool BPFMIPreEmitPeephole::removeMayGotoZero() {
688 bool Changed = false;
689 MachineBasicBlock *Prev_MBB, *Curr_MBB = nullptr;
690
691 for (MachineBasicBlock &MBB : make_early_inc_range(reverse(*MF))) {
692 Prev_MBB = Curr_MBB;
693 Curr_MBB = &MBB;
694 if (Prev_MBB == nullptr || Curr_MBB->empty())
695 continue;
696
697 MachineInstr &MI = Curr_MBB->back();
698 if (MI.getOpcode() != TargetOpcode::INLINEASM_BR)
699 continue;
700
701 const char *AsmStr = MI.getOperand(0).getSymbolName();
703 SplitString(AsmStr, AsmPieces, ";\n");
704
705 // Do not support multiple insns in one inline asm.
706 if (AsmPieces.size() != 1)
707 continue;
708
709 // The asm insn must be a may_goto insn.
710 SmallVector<StringRef, 4> AsmOpPieces;
711 SplitString(AsmPieces[0], AsmOpPieces, " ");
712 if (AsmOpPieces.size() != 2 || AsmOpPieces[0] != "may_goto")
713 continue;
714 // Enforce the format of 'may_goto <label>'.
715 if (AsmOpPieces[1] != "${0:l}" && AsmOpPieces[1] != "$0")
716 continue;
717
718 // Get the may_goto branch target.
719 MachineOperand &MO = MI.getOperand(InlineAsm::MIOp_FirstOperand + 1);
720 if (!MO.isMBB() || MO.getMBB() != Prev_MBB)
721 continue;
722
723 Changed = true;
724 if (Curr_MBB->begin() == MI) {
725 // Single 'may_goto' insn in the same basic block.
726 Curr_MBB->removeSuccessor(Prev_MBB);
727 for (MachineBasicBlock *Pred : Curr_MBB->predecessors())
728 Pred->replaceSuccessor(Curr_MBB, Prev_MBB);
729 Curr_MBB->eraseFromParent();
730 Curr_MBB = Prev_MBB;
731 } else {
732 // Remove 'may_goto' insn.
733 MI.eraseFromParent();
734 }
735 }
736
737 return Changed;
738}
739
740// If the last insn in a funciton is 'JAL &bpf_unreachable', let us add an
741// 'exit' insn after that insn. This will ensure no fallthrough at the last
742// insn, making kernel verification easier.
743bool BPFMIPreEmitPeephole::addExitAfterUnreachable() {
744 MachineBasicBlock &MBB = MF->back();
745 MachineInstr &MI = MBB.back();
746 if (MI.getOpcode() != BPF::JAL || !MI.getOperand(0).isGlobal() ||
747 MI.getOperand(0).getGlobal()->getName() != BPF_TRAP)
748 return false;
749
750 BuildMI(&MBB, MI.getDebugLoc(), TII->get(BPF::RET));
751 return true;
752}
753
754bool BPFMIPreEmitPeephole::expandStackArgPseudos() {
755 bool Changed = false;
756
757 for (MachineBasicBlock &MBB : *MF) {
758 for (auto It = MBB.begin(), End = MBB.end(); It != End;) {
759 MachineInstr &MI = *It++;
760 DebugLoc DL = MI.getDebugLoc();
761
762 switch (MI.getOpcode()) {
763 default:
764 break;
765
766 case BPF::LOAD_STACK_ARG_PSEUDO: {
767 Register DstReg = MI.getOperand(0).getReg();
768 int16_t Off = MI.getOperand(1).getImm();
769
770 BuildMI(MBB, MI, DL, TII->get(BPF::LDD), DstReg)
771 .addReg(BPF::R11)
772 .addImm(Off);
773 MI.eraseFromParent();
774 Changed = true;
775 break;
776 }
777
778 case BPF::STORE_STACK_ARG_PSEUDO: {
779 int16_t Off = MI.getOperand(0).getImm();
780 const MachineOperand &SrcMO = MI.getOperand(1);
781 Register SrcReg = SrcMO.getReg();
782 bool IsKill = SrcMO.isKill();
783
784 BuildMI(MBB, MI, DL, TII->get(BPF::STD))
785 .addReg(SrcReg, getKillRegState(IsKill))
786 .addReg(BPF::R11)
787 .addImm(Off);
788 MI.eraseFromParent();
789 Changed = true;
790 break;
791 }
792
793 case BPF::STORE_STACK_ARG_IMM_PSEUDO: {
794 int16_t Off = MI.getOperand(0).getImm();
795 int32_t Val = MI.getOperand(1).getImm();
796
797 BuildMI(MBB, MI, DL, TII->get(BPF::STD_imm))
798 .addImm(Val)
799 .addReg(BPF::R11)
800 .addImm(Off);
801 MI.eraseFromParent();
802 Changed = true;
803 break;
804 }
805 }
806 }
807 }
808
809 return Changed;
810}
811
812} // end default namespace
813
814INITIALIZE_PASS(BPFMIPreEmitPeephole, "bpf-mi-pemit-peephole",
815 "BPF PreEmit Peephole Optimization", false, false)
816
817char BPFMIPreEmitPeephole::ID = 0;
818FunctionPass* llvm::createBPFMIPreEmitPeepholePass()
819{
820 return new BPFMIPreEmitPeephole();
821}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static cl::opt< int > GotolAbsLowBound("gotol-abs-low-bound", cl::Hidden, cl::init(INT16_MAX > > 1), cl::desc("Specify gotol lower bound"))
#define BPF_TRAP
Definition BPF.h:25
#define DEBUG_TYPE
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
This file implements the LivePhysRegs utility for tracking liveness of physical registers.
#define I(x, y, z)
Definition MD5.cpp:57
Register Reg
Register const TargetRegisterInfo * TRI
Promote Memory to Register
Definition Mem2Reg.cpp:110
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Definition Statistic.h:171
This file contains some functions that are useful when dealing with strings.
#define LLVM_DEBUG(...)
Definition Debug.h:119
static void initialize(TargetLibraryInfoImpl &TLI, const Triple &T, const llvm::StringTable &StandardNames, VectorLibrary VecLib)
Initialize the set of available library functions based on the specified target triple.
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
const BasicBlock * getBasicBlock() const
Return the LLVM basic block that this instance corresponded to originally.
LLVM_ABI void addSuccessor(MachineBasicBlock *Succ, BranchProbability Prob=BranchProbability::getUnknown())
Add Succ as a successor of this MachineBasicBlock.
LLVM_ABI void removeSuccessor(MachineBasicBlock *Succ, bool NormalizeSuccProbs=false)
Remove successor from the successors list of this MachineBasicBlock.
LLVM_ABI void eraseFromParent()
This method unlinks 'this' from the containing function and deletes it.
iterator_range< iterator > terminators()
iterator_range< pred_iterator > predecessors()
MachineInstrBundleIterator< MachineInstr > iterator
int getObjectIndexEnd() const
Return one past the maximum frame object index.
LLVM_ABI int CreateFixedSpillStackObject(uint64_t Size, int64_t SPOffset, bool IsImmutable=false)
Create a spill slot at a fixed location on the stack.
int64_t getObjectOffset(int ObjectIdx) const
Return the assigned stack offset of the specified object from the incoming stack pointer.
int getObjectIndexBegin() const
Return the minimum frame object index.
bool isDeadObjectIndex(int ObjectIdx) const
Returns true if the specified index corresponds to a dead object.
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Function & getFunction()
Return the LLVM function that this machine code represents.
BasicBlockListType::iterator iterator
const MachineInstrBuilder & addReg(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a new virtual register operand.
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addMBB(MachineBasicBlock *MBB, unsigned TargetFlags=0) const
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
unsigned getNumOperands() const
Retuns the total number of operands.
const DebugLoc & getDebugLoc() const
Returns the debug location id of this MachineInstr.
LLVM_ABI void dump() const
const MachineOperand & getOperand(unsigned i) const
LLVM_ABI MachineInstrBundleIterator< MachineInstr > eraseFromParent()
Unlink 'this' from the containing basic block and delete it.
int64_t getImm() const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
MachineBasicBlock * getMBB() const
Register getReg() const
getReg - Returns the register number.
bool isMBB() const
isMBB - Tests if this is a MO_MachineBasicBlock operand.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
const TargetRegisterClass * getRegClass(Register Reg) const
Return the register class of the specified virtual register.
LLVM_ABI MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
void dump() const
Definition Pass.cpp:146
constexpr bool isVirtual() const
Return true if the specified register number is in the virtual register namespace.
Definition Register.h:79
void push_back(const T &Elt)
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
self_iterator getIterator()
Definition ilist_node.h:123
CallInst * Call
Changed
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
@ BasicBlock
Various leaf nodes.
Definition ISDOpcodes.h:81
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
constexpr RegState getKillRegState(bool B)
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
Definition STLExtras.h:633
FunctionPass * createBPFMIPreEmitPeepholePass()
LLVM_ABI void SplitString(StringRef Source, SmallVectorImpl< StringRef > &OutFragments, StringRef Delimiters=" \t\n\v\f\r")
SplitString - Split up the specified string according to the specified delimiters,...
FunctionPass * createBPFMIPeepholePass()
auto reverse(ContainerTy &&C)
Definition STLExtras.h:407
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
uint16_t MCPhysReg
An unsigned integer type large enough to represent all physical registers, but not necessarily virtua...
Definition MCRegister.h:21