aboutsummaryrefslogtreecommitdiff
path: root/lib/Target/BPF/BPFMIPeephole.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Target/BPF/BPFMIPeephole.cpp')
-rw-r--r--lib/Target/BPF/BPFMIPeephole.cpp284
1 files changed, 284 insertions, 0 deletions
diff --git a/lib/Target/BPF/BPFMIPeephole.cpp b/lib/Target/BPF/BPFMIPeephole.cpp
new file mode 100644
index 000000000000..9e984d0facfb
--- /dev/null
+++ b/lib/Target/BPF/BPFMIPeephole.cpp
@@ -0,0 +1,284 @@
+//===-------------- BPFMIPeephole.cpp - MI Peephole Cleanups -------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass performs peephole optimizations to cleanup ugly code sequences at
+// MachineInstruction layer.
+//
+// Currently, there are two optimizations implemented:
+// - One pre-RA MachineSSA pass to eliminate type promotion sequences, those
+// zero extend 32-bit subregisters to 64-bit registers, if the compiler
+// could prove the subregisters is defined by 32-bit operations in which
+// case the upper half of the underlying 64-bit registers were zeroed
+// implicitly.
+//
+// - One post-RA PreEmit pass to do final cleanup on some redundant
+// instructions generated due to bad RA on subregister.
+//===----------------------------------------------------------------------===//
+
+#include "BPF.h"
+#include "BPFInstrInfo.h"
+#include "BPFTargetMachine.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "bpf-mi-zext-elim"
+
+STATISTIC(ZExtElemNum, "Number of zero extension shifts eliminated");
+
+namespace {
+
+struct BPFMIPeephole : public MachineFunctionPass {
+
+ static char ID;
+ const BPFInstrInfo *TII;
+ MachineFunction *MF;
+ MachineRegisterInfo *MRI;
+
+ BPFMIPeephole() : MachineFunctionPass(ID) {
+ initializeBPFMIPeepholePass(*PassRegistry::getPassRegistry());
+ }
+
+private:
+ // Initialize class variables.
+ void initialize(MachineFunction &MFParm);
+
+ bool isMovFrom32Def(MachineInstr *MovMI);
+ bool eliminateZExtSeq(void);
+
+public:
+
+ // Main entry point for this pass.
+ bool runOnMachineFunction(MachineFunction &MF) override {
+ if (skipFunction(MF.getFunction()))
+ return false;
+
+ initialize(MF);
+
+ return eliminateZExtSeq();
+ }
+};
+
+// Initialize class variables.
+void BPFMIPeephole::initialize(MachineFunction &MFParm) {
+ MF = &MFParm;
+ MRI = &MF->getRegInfo();
+ TII = MF->getSubtarget<BPFSubtarget>().getInstrInfo();
+ LLVM_DEBUG(dbgs() << "*** BPF MachineSSA peephole pass ***\n\n");
+}
+
+bool BPFMIPeephole::isMovFrom32Def(MachineInstr *MovMI)
+{
+ MachineInstr *DefInsn = MRI->getVRegDef(MovMI->getOperand(1).getReg());
+
+ LLVM_DEBUG(dbgs() << " Def of Mov Src:");
+ LLVM_DEBUG(DefInsn->dump());
+
+ if (!DefInsn)
+ return false;
+
+ if (DefInsn->isPHI()) {
+ for (unsigned i = 1, e = DefInsn->getNumOperands(); i < e; i += 2) {
+ MachineOperand &opnd = DefInsn->getOperand(i);
+
+ if (!opnd.isReg())
+ return false;
+
+ MachineInstr *PhiDef = MRI->getVRegDef(opnd.getReg());
+ // quick check on PHI incoming definitions.
+ if (!PhiDef || PhiDef->isPHI() || PhiDef->getOpcode() == BPF::COPY)
+ return false;
+ }
+ }
+
+ if (DefInsn->getOpcode() == BPF::COPY) {
+ MachineOperand &opnd = DefInsn->getOperand(1);
+
+ if (!opnd.isReg())
+ return false;
+
+ unsigned Reg = opnd.getReg();
+ if ((TargetRegisterInfo::isVirtualRegister(Reg) &&
+ MRI->getRegClass(Reg) == &BPF::GPRRegClass))
+ return false;
+ }
+
+ LLVM_DEBUG(dbgs() << " One ZExt elim sequence identified.\n");
+
+ return true;
+}
+
+bool BPFMIPeephole::eliminateZExtSeq(void) {
+ MachineInstr* ToErase = nullptr;
+ bool Eliminated = false;
+
+ for (MachineBasicBlock &MBB : *MF) {
+ for (MachineInstr &MI : MBB) {
+ // If the previous instruction was marked for elimination, remove it now.
+ if (ToErase) {
+ ToErase->eraseFromParent();
+ ToErase = nullptr;
+ }
+
+ // Eliminate the 32-bit to 64-bit zero extension sequence when possible.
+ //
+ // MOV_32_64 rB, wA
+ // SLL_ri rB, rB, 32
+ // SRL_ri rB, rB, 32
+ if (MI.getOpcode() == BPF::SRL_ri &&
+ MI.getOperand(2).getImm() == 32) {
+ unsigned DstReg = MI.getOperand(0).getReg();
+ unsigned ShfReg = MI.getOperand(1).getReg();
+ MachineInstr *SllMI = MRI->getVRegDef(ShfReg);
+
+ LLVM_DEBUG(dbgs() << "Starting SRL found:");
+ LLVM_DEBUG(MI.dump());
+
+ if (!SllMI ||
+ SllMI->isPHI() ||
+ SllMI->getOpcode() != BPF::SLL_ri ||
+ SllMI->getOperand(2).getImm() != 32)
+ continue;
+
+ LLVM_DEBUG(dbgs() << " SLL found:");
+ LLVM_DEBUG(SllMI->dump());
+
+ MachineInstr *MovMI = MRI->getVRegDef(SllMI->getOperand(1).getReg());
+ if (!MovMI ||
+ MovMI->isPHI() ||
+ MovMI->getOpcode() != BPF::MOV_32_64)
+ continue;
+
+ LLVM_DEBUG(dbgs() << " Type cast Mov found:");
+ LLVM_DEBUG(MovMI->dump());
+
+ unsigned SubReg = MovMI->getOperand(1).getReg();
+ if (!isMovFrom32Def(MovMI)) {
+ LLVM_DEBUG(dbgs()
+ << " One ZExt elim sequence failed qualifying elim.\n");
+ continue;
+ }
+
+ BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(BPF::SUBREG_TO_REG), DstReg)
+ .addImm(0).addReg(SubReg).addImm(BPF::sub_32);
+
+ SllMI->eraseFromParent();
+ MovMI->eraseFromParent();
+ // MI is the right shift, we can't erase it in it's own iteration.
+ // Mark it to ToErase, and erase in the next iteration.
+ ToErase = &MI;
+ ZExtElemNum++;
+ Eliminated = true;
+ }
+ }
+ }
+
+ return Eliminated;
+}
+
+} // end default namespace
+
+INITIALIZE_PASS(BPFMIPeephole, DEBUG_TYPE,
+ "BPF MachineSSA Peephole Optimization", false, false)
+
+char BPFMIPeephole::ID = 0;
+FunctionPass* llvm::createBPFMIPeepholePass() { return new BPFMIPeephole(); }
+
+STATISTIC(RedundantMovElemNum, "Number of redundant moves eliminated");
+
+namespace {
+
+struct BPFMIPreEmitPeephole : public MachineFunctionPass {
+
+ static char ID;
+ MachineFunction *MF;
+ const TargetRegisterInfo *TRI;
+
+ BPFMIPreEmitPeephole() : MachineFunctionPass(ID) {
+ initializeBPFMIPreEmitPeepholePass(*PassRegistry::getPassRegistry());
+ }
+
+private:
+ // Initialize class variables.
+ void initialize(MachineFunction &MFParm);
+
+ bool eliminateRedundantMov(void);
+
+public:
+
+ // Main entry point for this pass.
+ bool runOnMachineFunction(MachineFunction &MF) override {
+ if (skipFunction(MF.getFunction()))
+ return false;
+
+ initialize(MF);
+
+ return eliminateRedundantMov();
+ }
+};
+
+// Initialize class variables.
+void BPFMIPreEmitPeephole::initialize(MachineFunction &MFParm) {
+ MF = &MFParm;
+ TRI = MF->getSubtarget<BPFSubtarget>().getRegisterInfo();
+ LLVM_DEBUG(dbgs() << "*** BPF PreEmit peephole pass ***\n\n");
+}
+
+bool BPFMIPreEmitPeephole::eliminateRedundantMov(void) {
+ MachineInstr* ToErase = nullptr;
+ bool Eliminated = false;
+
+ for (MachineBasicBlock &MBB : *MF) {
+ for (MachineInstr &MI : MBB) {
+ // If the previous instruction was marked for elimination, remove it now.
+ if (ToErase) {
+ LLVM_DEBUG(dbgs() << " Redundant Mov Eliminated:");
+ LLVM_DEBUG(ToErase->dump());
+ ToErase->eraseFromParent();
+ ToErase = nullptr;
+ }
+
+ // Eliminate identical move:
+ //
+ // MOV rA, rA
+ //
+ // This is particularly possible to happen when sub-register support
+ // enabled. The special type cast insn MOV_32_64 involves different
+ // register class on src (i32) and dst (i64), RA could generate useless
+ // instruction due to this.
+ if (MI.getOpcode() == BPF::MOV_32_64) {
+ unsigned dst = MI.getOperand(0).getReg();
+ unsigned dst_sub = TRI->getSubReg(dst, BPF::sub_32);
+ unsigned src = MI.getOperand(1).getReg();
+
+ if (dst_sub != src)
+ continue;
+
+ ToErase = &MI;
+ RedundantMovElemNum++;
+ Eliminated = true;
+ }
+ }
+ }
+
+ return Eliminated;
+}
+
+} // end default namespace
+
+INITIALIZE_PASS(BPFMIPreEmitPeephole, "bpf-mi-pemit-peephole",
+ "BPF PreEmit Peephole Optimization", false, false)
+
+char BPFMIPreEmitPeephole::ID = 0;
+FunctionPass* llvm::createBPFMIPreEmitPeepholePass()
+{
+ return new BPFMIPreEmitPeephole();
+}