diff options
| author | Yonghong Song <yhs@fb.com> | 2019-11-20 09:52:29 -0800 |
|---|---|---|
| committer | Yonghong Song <yhs@fb.com> | 2019-11-20 15:19:59 -0800 |
| commit | a0841dfe8594f189d79f3612fec019eda4824474 (patch) | |
| tree | 005678a38852d201ac221fa7b25e49b3b5169ca1 /llvm/lib/Target/BPF | |
| parent | cd8748a15f2d18861b3548eb26ed2b52e5ee50b4 (diff) | |
| download | bcm5719-llvm-a0841dfe8594f189d79f3612fec019eda4824474.tar.gz bcm5719-llvm-a0841dfe8594f189d79f3612fec019eda4824474.zip | |
[BPF] Fix a bug in peephole optimization
One of current peephole optimiations is to remove SLL/SRL if
the sub register has been zero extended. This phase has two bugs
and one limitations.
First, for the physical subregister used in pseudo insn COPY
like below, it permits incorrect optimization.
%0:gpr32 = COPY $w0
...
%4:gpr = MOV_32_64 %0:gpr32
%5:gpr = SLL_ri %4:gpr(tied-def 0), 32
%6:gpr = SRA_ri %5:gpr(tied-def 0), 32
The $w0 could be from the return value of a previous function call
and its upper 32-bit value might contain some non-zero values.
The same applies to function arguments.
Second, the current code may permits removing SLL/SRA like below:
%0:gpr32 = COPY $w0
%1:gpr32 = COPY %0:gpr32
...
%4:gpr = MOV_32_64 %1:gpr32
%5:gpr = SLL_ri %4:gpr(tied-def 0), 32
%6:gpr = SRA_ri %5:gpr(tied-def 0), 32
The reason is that it did not follow def-use chain to skip all
intermediate 32bit-to-32bit COPY instructions.
The current implementation is also very conservative for PHI
instructions. If any PHI insn component is another PHI or COPY insn,
it will just permit SLL/SRA.
This patch fixed the issue as follows:
- During def/use chain traversal, if any physical register is read,
SLL/SRA will be preserved as these physical registers are mostly
from function return values or current function arguments.
- Recursively visit all COPY and PHI instructions.
Diffstat (limited to 'llvm/lib/Target/BPF')
| -rw-r--r-- | llvm/lib/Target/BPF/BPFMIPeephole.cpp | 80 |
1 files changed, 59 insertions, 21 deletions
diff --git a/llvm/lib/Target/BPF/BPFMIPeephole.cpp b/llvm/lib/Target/BPF/BPFMIPeephole.cpp index e9eecc55c3c..c0f99fa2b44 100644 --- a/llvm/lib/Target/BPF/BPFMIPeephole.cpp +++ b/llvm/lib/Target/BPF/BPFMIPeephole.cpp @@ -51,6 +51,9 @@ private: // Initialize class variables. void initialize(MachineFunction &MFParm); + bool isCopyFrom32Def(MachineInstr *CopyMI); + bool isInsnFrom32Def(MachineInstr *DefInsn); + bool isPhiFrom32Def(MachineInstr *MovMI); bool isMovFrom32Def(MachineInstr *MovMI); bool eliminateZExtSeq(void); @@ -75,42 +78,77 @@ void BPFMIPeephole::initialize(MachineFunction &MFParm) { LLVM_DEBUG(dbgs() << "*** BPF MachineSSA ZEXT Elim peephole pass ***\n\n"); } -bool BPFMIPeephole::isMovFrom32Def(MachineInstr *MovMI) +bool BPFMIPeephole::isCopyFrom32Def(MachineInstr *CopyMI) { - MachineInstr *DefInsn = MRI->getVRegDef(MovMI->getOperand(1).getReg()); + MachineOperand &opnd = CopyMI->getOperand(1); - LLVM_DEBUG(dbgs() << " Def of Mov Src:"); - LLVM_DEBUG(DefInsn->dump()); + if (!opnd.isReg()) + return false; - if (!DefInsn) + // Return false if getting value from a 32bit physical register. + // Most likely, this physical register is aliased to + // function call return value or current function parameters. + Register Reg = opnd.getReg(); + if (!Register::isVirtualRegister(Reg)) return false; - if (DefInsn->isPHI()) { - for (unsigned i = 1, e = DefInsn->getNumOperands(); i < e; i += 2) { - MachineOperand &opnd = DefInsn->getOperand(i); + if (MRI->getRegClass(Reg) == &BPF::GPRRegClass) + return false; - if (!opnd.isReg()) - return false; + MachineInstr *DefInsn = MRI->getVRegDef(Reg); + if (!isInsnFrom32Def(DefInsn)) + return false; - MachineInstr *PhiDef = MRI->getVRegDef(opnd.getReg()); - // quick check on PHI incoming definitions. - if (!PhiDef || PhiDef->isPHI() || PhiDef->getOpcode() == BPF::COPY) - return false; - } - } + return true; +} - if (DefInsn->getOpcode() == BPF::COPY) { - MachineOperand &opnd = DefInsn->getOperand(1); +bool BPFMIPeephole::isPhiFrom32Def(MachineInstr *PhiMI) +{ + for (unsigned i = 1, e = PhiMI->getNumOperands(); i < e; i += 2) { + MachineOperand &opnd = PhiMI->getOperand(i); if (!opnd.isReg()) return false; - Register Reg = opnd.getReg(); - if ((Register::isVirtualRegister(Reg) && - MRI->getRegClass(Reg) == &BPF::GPRRegClass)) + MachineInstr *PhiDef = MRI->getVRegDef(opnd.getReg()); + if (!PhiDef) + return false; + if (PhiDef->isPHI() && !isPhiFrom32Def(PhiDef)) + return false; + if (PhiDef->getOpcode() == BPF::COPY && !isCopyFrom32Def(PhiDef)) + return false; + } + + return true; +} + +// The \p DefInsn instruction defines a virtual register. +bool BPFMIPeephole::isInsnFrom32Def(MachineInstr *DefInsn) +{ + if (!DefInsn) + return false; + + if (DefInsn->isPHI()) { + if (!isPhiFrom32Def(DefInsn)) + return false; + } else if (DefInsn->getOpcode() == BPF::COPY) { + if (!isCopyFrom32Def(DefInsn)) return false; } + return true; +} + +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 (!isInsnFrom32Def(DefInsn)) + return false; + LLVM_DEBUG(dbgs() << " One ZExt elim sequence identified.\n"); return true; |

