2018-02-24 00:49:32 +01:00
|
|
|
//===-------------- BPFMIPeephole.cpp - MI Peephole Cleanups -------------===//
|
|
|
|
//
|
2019-01-19 09:50:56 +01:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2018-02-24 00:49:32 +01:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This pass performs peephole optimizations to cleanup ugly code sequences at
|
|
|
|
// MachineInstruction layer.
|
|
|
|
//
|
2018-03-13 07:47:06 +01:00
|
|
|
// 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.
|
2018-02-24 00:49:32 +01:00
|
|
|
//
|
2018-03-13 07:47:06 +01:00
|
|
|
// - One post-RA PreEmit pass to do final cleanup on some redundant
|
|
|
|
// instructions generated due to bad RA on subregister.
|
2018-02-24 00:49:32 +01:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#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;
|
|
|
|
|
2018-03-13 07:47:03 +01:00
|
|
|
#define DEBUG_TYPE "bpf-mi-zext-elim"
|
2018-02-24 00:49:32 +01:00
|
|
|
|
2018-03-13 07:47:03 +01:00
|
|
|
STATISTIC(ZExtElemNum, "Number of zero extension shifts eliminated");
|
2018-02-24 00:49:32 +01:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2018-03-13 07:47:03 +01:00
|
|
|
bool isMovFrom32Def(MachineInstr *MovMI);
|
|
|
|
bool eliminateZExtSeq(void);
|
2018-02-24 00:49:32 +01:00
|
|
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
// Main entry point for this pass.
|
|
|
|
bool runOnMachineFunction(MachineFunction &MF) override {
|
|
|
|
if (skipFunction(MF.getFunction()))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
initialize(MF);
|
|
|
|
|
2018-03-13 07:47:03 +01:00
|
|
|
return eliminateZExtSeq();
|
2018-02-24 00:49:32 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// Initialize class variables.
|
|
|
|
void BPFMIPeephole::initialize(MachineFunction &MFParm) {
|
|
|
|
MF = &MFParm;
|
|
|
|
MRI = &MF->getRegInfo();
|
|
|
|
TII = MF->getSubtarget<BPFSubtarget>().getInstrInfo();
|
2018-05-14 14:53:11 +02:00
|
|
|
LLVM_DEBUG(dbgs() << "*** BPF MachineSSA peephole pass ***\n\n");
|
2018-02-24 00:49:32 +01:00
|
|
|
}
|
|
|
|
|
2018-03-13 07:47:03 +01:00
|
|
|
bool BPFMIPeephole::isMovFrom32Def(MachineInstr *MovMI)
|
|
|
|
{
|
|
|
|
MachineInstr *DefInsn = MRI->getVRegDef(MovMI->getOperand(1).getReg());
|
2018-02-24 00:49:32 +01:00
|
|
|
|
2018-05-14 14:53:11 +02:00
|
|
|
LLVM_DEBUG(dbgs() << " Def of Mov Src:");
|
|
|
|
LLVM_DEBUG(DefInsn->dump());
|
2018-03-13 07:47:07 +01:00
|
|
|
|
2018-03-13 07:47:04 +01:00
|
|
|
if (!DefInsn)
|
2018-03-13 07:47:03 +01:00
|
|
|
return false;
|
2018-02-24 00:49:32 +01:00
|
|
|
|
2018-03-13 07:47:04 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-13 07:47:03 +01:00
|
|
|
if (DefInsn->getOpcode() == BPF::COPY) {
|
|
|
|
MachineOperand &opnd = DefInsn->getOperand(1);
|
bpf: Tighten subregister definition check
The current subregister definition check stops after the MOV_32_64
instruction.
This means we are thinking all the following instruction sequences
are safe to be eliminated:
MOV_32_64 rB, wA
SLL_ri rB, rB, 32
SRL_ri rB, rB, 32
However, this is *not* true. The source subregister wA of MOV_32_64 could
come from a implicit truncation of 64-bit register in which case the high
bits of the 64-bit register is not zeroed, therefore we can't eliminate
above sequence.
For example, for i32_val, we shouldn't do the elimination:
long long bar ();
int foo (int b, int c)
{
unsigned int i32_val = (unsigned int) bar();
if (i32_val < 10)
return b;
else
return c;
}
Signed-off-by: Jiong Wang <jiong.wang@netronome.com>
Signed-off-by: Yonghong Song <yhs@fb.com>
llvm-svn: 327365
2018-03-13 07:47:00 +01:00
|
|
|
|
|
|
|
if (!opnd.isReg())
|
2018-03-13 07:47:03 +01:00
|
|
|
return false;
|
bpf: Tighten subregister definition check
The current subregister definition check stops after the MOV_32_64
instruction.
This means we are thinking all the following instruction sequences
are safe to be eliminated:
MOV_32_64 rB, wA
SLL_ri rB, rB, 32
SRL_ri rB, rB, 32
However, this is *not* true. The source subregister wA of MOV_32_64 could
come from a implicit truncation of 64-bit register in which case the high
bits of the 64-bit register is not zeroed, therefore we can't eliminate
above sequence.
For example, for i32_val, we shouldn't do the elimination:
long long bar ();
int foo (int b, int c)
{
unsigned int i32_val = (unsigned int) bar();
if (i32_val < 10)
return b;
else
return c;
}
Signed-off-by: Jiong Wang <jiong.wang@netronome.com>
Signed-off-by: Yonghong Song <yhs@fb.com>
llvm-svn: 327365
2018-03-13 07:47:00 +01:00
|
|
|
|
|
|
|
unsigned Reg = opnd.getReg();
|
2019-08-02 01:27:28 +02:00
|
|
|
if ((Register::isVirtualRegister(Reg) &&
|
2018-03-13 07:47:03 +01:00
|
|
|
MRI->getRegClass(Reg) == &BPF::GPRRegClass))
|
2019-08-02 01:27:28 +02:00
|
|
|
return false;
|
bpf: Tighten subregister definition check
The current subregister definition check stops after the MOV_32_64
instruction.
This means we are thinking all the following instruction sequences
are safe to be eliminated:
MOV_32_64 rB, wA
SLL_ri rB, rB, 32
SRL_ri rB, rB, 32
However, this is *not* true. The source subregister wA of MOV_32_64 could
come from a implicit truncation of 64-bit register in which case the high
bits of the 64-bit register is not zeroed, therefore we can't eliminate
above sequence.
For example, for i32_val, we shouldn't do the elimination:
long long bar ();
int foo (int b, int c)
{
unsigned int i32_val = (unsigned int) bar();
if (i32_val < 10)
return b;
else
return c;
}
Signed-off-by: Jiong Wang <jiong.wang@netronome.com>
Signed-off-by: Yonghong Song <yhs@fb.com>
llvm-svn: 327365
2018-03-13 07:47:00 +01:00
|
|
|
}
|
|
|
|
|
2018-05-14 14:53:11 +02:00
|
|
|
LLVM_DEBUG(dbgs() << " One ZExt elim sequence identified.\n");
|
2018-03-13 07:47:07 +01:00
|
|
|
|
2018-03-13 07:47:03 +01:00
|
|
|
return true;
|
2018-02-24 00:49:32 +01:00
|
|
|
}
|
|
|
|
|
2018-03-13 07:47:03 +01:00
|
|
|
bool BPFMIPeephole::eliminateZExtSeq(void) {
|
|
|
|
MachineInstr* ToErase = nullptr;
|
2018-02-24 00:49:32 +01:00
|
|
|
bool Eliminated = false;
|
|
|
|
|
|
|
|
for (MachineBasicBlock &MBB : *MF) {
|
|
|
|
for (MachineInstr &MI : MBB) {
|
2018-03-13 07:47:03 +01:00
|
|
|
// 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);
|
|
|
|
|
2018-05-14 14:53:11 +02:00
|
|
|
LLVM_DEBUG(dbgs() << "Starting SRL found:");
|
|
|
|
LLVM_DEBUG(MI.dump());
|
2018-03-13 07:47:07 +01:00
|
|
|
|
2018-03-13 07:47:03 +01:00
|
|
|
if (!SllMI ||
|
|
|
|
SllMI->isPHI() ||
|
|
|
|
SllMI->getOpcode() != BPF::SLL_ri ||
|
|
|
|
SllMI->getOperand(2).getImm() != 32)
|
|
|
|
continue;
|
|
|
|
|
2018-05-14 14:53:11 +02:00
|
|
|
LLVM_DEBUG(dbgs() << " SLL found:");
|
|
|
|
LLVM_DEBUG(SllMI->dump());
|
2018-03-13 07:47:07 +01:00
|
|
|
|
2018-03-13 07:47:03 +01:00
|
|
|
MachineInstr *MovMI = MRI->getVRegDef(SllMI->getOperand(1).getReg());
|
|
|
|
if (!MovMI ||
|
|
|
|
MovMI->isPHI() ||
|
|
|
|
MovMI->getOpcode() != BPF::MOV_32_64)
|
|
|
|
continue;
|
|
|
|
|
2018-05-14 14:53:11 +02:00
|
|
|
LLVM_DEBUG(dbgs() << " Type cast Mov found:");
|
|
|
|
LLVM_DEBUG(MovMI->dump());
|
2018-03-13 07:47:07 +01:00
|
|
|
|
2018-03-13 07:47:04 +01:00
|
|
|
unsigned SubReg = MovMI->getOperand(1).getReg();
|
2018-03-13 07:47:07 +01:00
|
|
|
if (!isMovFrom32Def(MovMI)) {
|
2018-05-14 14:53:11 +02:00
|
|
|
LLVM_DEBUG(dbgs()
|
|
|
|
<< " One ZExt elim sequence failed qualifying elim.\n");
|
2018-03-13 07:47:03 +01:00
|
|
|
continue;
|
2018-03-13 07:47:07 +01:00
|
|
|
}
|
2018-03-13 07:47:03 +01:00
|
|
|
|
|
|
|
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;
|
2018-02-24 00:49:32 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Eliminated;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // end default namespace
|
|
|
|
|
2018-03-13 07:47:06 +01:00
|
|
|
INITIALIZE_PASS(BPFMIPeephole, DEBUG_TYPE,
|
|
|
|
"BPF MachineSSA Peephole Optimization", false, false)
|
2018-02-24 00:49:32 +01:00
|
|
|
|
|
|
|
char BPFMIPeephole::ID = 0;
|
|
|
|
FunctionPass* llvm::createBPFMIPeepholePass() { return new BPFMIPeephole(); }
|
2018-03-13 07:47:06 +01:00
|
|
|
|
|
|
|
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();
|
2018-05-14 14:53:11 +02:00
|
|
|
LLVM_DEBUG(dbgs() << "*** BPF PreEmit peephole pass ***\n\n");
|
2018-03-13 07:47:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
2018-05-14 14:53:11 +02:00
|
|
|
LLVM_DEBUG(dbgs() << " Redundant Mov Eliminated:");
|
|
|
|
LLVM_DEBUG(ToErase->dump());
|
2018-03-13 07:47:06 +01:00
|
|
|
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();
|
|
|
|
}
|