ARM: peephole optimization to remove cmp instruction

This patch will optimize the following cases:
  sub r1, r3 | sub r1, imm
  cmp r3, r1 or cmp r1, r3 | cmp r1, imm
  bge L1

TO
  subs r1, r3
  bge  L1 or ble L1

If the branch instruction can use flag from "sub", then we can replace
"sub" with "subs" and eliminate the "cmp" instruction.

rdar: 10734411


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@156599 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Manman Ren 2012-05-11 01:30:47 +00:00
parent d4347e1af9
commit 247c5ab07c
3 changed files with 162 additions and 27 deletions

View File

@ -31,6 +31,15 @@
// same flag that the "cmp" instruction sets and that "bz" uses, then we can // same flag that the "cmp" instruction sets and that "bz" uses, then we can
// eliminate the "cmp" instruction. // eliminate the "cmp" instruction.
// //
// Another instance, in this code:
//
// sub r1, r3 | sub r1, imm
// cmp r3, r1 or cmp r1, r3 | cmp r1, imm
// bge L1
//
// If the branch instruction can use flag from "sub", then we can replace
// "sub" with "subs" and eliminate the "cmp" instruction.
//
// - Optimize Bitcast pairs: // - Optimize Bitcast pairs:
// //
// v1 = bitcast v0 // v1 = bitcast v0

View File

@ -1753,6 +1753,12 @@ AnalyzeCompare(const MachineInstr *MI, unsigned &SrcReg, int &CmpMask,
CmpMask = ~0; CmpMask = ~0;
CmpValue = MI->getOperand(1).getImm(); CmpValue = MI->getOperand(1).getImm();
return true; return true;
case ARM::CMPrr:
case ARM::t2CMPrr:
SrcReg = MI->getOperand(0).getReg();
CmpMask = ~0;
CmpValue = 0;
return true;
case ARM::TSTri: case ARM::TSTri:
case ARM::t2TSTri: case ARM::t2TSTri:
SrcReg = MI->getOperand(0).getReg(); SrcReg = MI->getOperand(0).getReg();
@ -1794,12 +1800,13 @@ static bool isSuitableForMask(MachineInstr *&MI, unsigned SrcReg,
} }
/// OptimizeCompareInstr - Convert the instruction supplying the argument to the /// OptimizeCompareInstr - Convert the instruction supplying the argument to the
/// comparison into one that sets the zero bit in the flags register. /// comparison into one that sets the zero bit in the flags register. Convert
/// the SUBrr(r1,r2)|Subri(r1,CmpValue) instruction into one that sets the flags
/// register and remove the CMPrr(r1,r2)|CMPrr(r2,r1)|CMPri(r1,CmpValue)
/// instruction.
bool ARMBaseInstrInfo:: bool ARMBaseInstrInfo::
OptimizeCompareInstr(MachineInstr *CmpInstr, unsigned SrcReg, int CmpMask, OptimizeCompareInstr(MachineInstr *CmpInstr, unsigned SrcReg, int CmpMask,
int CmpValue, const MachineRegisterInfo *MRI) const { int CmpValue, const MachineRegisterInfo *MRI) const {
if (CmpValue != 0)
return false;
MachineRegisterInfo::def_iterator DI = MRI->def_begin(SrcReg); MachineRegisterInfo::def_iterator DI = MRI->def_begin(SrcReg);
if (llvm::next(DI) != MRI->def_end()) if (llvm::next(DI) != MRI->def_end())
@ -1825,18 +1832,37 @@ OptimizeCompareInstr(MachineInstr *CmpInstr, unsigned SrcReg, int CmpMask,
} }
} }
// Conservatively refuse to convert an instruction which isn't in the same BB // Get ready to iterate backward from CmpInstr.
// as the comparison. MachineBasicBlock::iterator I = CmpInstr, E = MI,
if (MI->getParent() != CmpInstr->getParent()) B = CmpInstr->getParent()->begin();
return false;
// Check that CPSR isn't set between the comparison instruction and the one we
// want to change.
MachineBasicBlock::iterator I = CmpInstr,E = MI, B = MI->getParent()->begin();
// Early exit if CmpInstr is at the beginning of the BB. // Early exit if CmpInstr is at the beginning of the BB.
if (I == B) return false; if (I == B) return false;
// There are two possible candidates which can be changed to set CPSR:
// One is MI, the other is a SUB instruction.
// For CMPrr(r1,r2), we are looking for SUB(r1,r2) or SUB(r2,r1).
// For CMPri(r1, CmpValue), we are looking for SUBri(r1, CmpValue).
MachineInstr *Sub = NULL;
unsigned SrcReg2 = 0;
if (CmpInstr->getOpcode() == ARM::CMPrr ||
CmpInstr->getOpcode() == ARM::t2CMPrr) {
SrcReg2 = CmpInstr->getOperand(1).getReg();
// MI is not a candidate for CMPrr.
MI = NULL;
} else if (MI->getParent() != CmpInstr->getParent() || CmpValue != 0) {
// Conservatively refuse to convert an instruction which isn't in the same
// BB as the comparison.
// For CMPri, we need to check Sub, thus we can't return here.
if(CmpInstr->getOpcode() == ARM::CMPri ||
CmpInstr->getOpcode() == ARM::t2CMPri)
MI = NULL;
else
return false;
}
// Check that CPSR isn't set between the comparison instruction and the one we
// want to change. At the same time, search for Sub.
--I; --I;
for (; I != E; --I) { for (; I != E; --I) {
const MachineInstr &Instr = *I; const MachineInstr &Instr = *I;
@ -1853,12 +1879,38 @@ OptimizeCompareInstr(MachineInstr *CmpInstr, unsigned SrcReg, int CmpMask,
return false; return false;
} }
// Check whether the current instruction is SUB(r1, r2) or SUB(r2, r1).
if (SrcReg2 != 0 && Instr.getOpcode() == ARM::SUBrr &&
((Instr.getOperand(1).getReg() == SrcReg &&
Instr.getOperand(2).getReg() == SrcReg2) ||
(Instr.getOperand(1).getReg() == SrcReg2 &&
Instr.getOperand(2).getReg() == SrcReg))) {
Sub = &*I;
break;
}
// Check whether the current instruction is SUBri(r1, CmpValue).
if ((CmpInstr->getOpcode() == ARM::CMPri ||
CmpInstr->getOpcode() == ARM::t2CMPri) &&
Instr.getOpcode() == ARM::SUBri && CmpValue != 0 &&
Instr.getOperand(1).getReg() == SrcReg &&
Instr.getOperand(2).getImm() == CmpValue) {
Sub = &*I;
break;
}
if (I == B) if (I == B)
// The 'and' is below the comparison instruction. // The 'and' is below the comparison instruction.
return false; return false;
} }
// Set the "zero" bit in CPSR. // Return false if no candidates exist.
if (!MI && !Sub)
return false;
// The single candidate is called MI.
if (!MI) MI = Sub;
switch (MI->getOpcode()) { switch (MI->getOpcode()) {
default: break; default: break;
case ARM::RSBrr: case ARM::RSBrr:
@ -1894,13 +1946,16 @@ OptimizeCompareInstr(MachineInstr *CmpInstr, unsigned SrcReg, int CmpMask,
case ARM::EORri: case ARM::EORri:
case ARM::t2EORrr: case ARM::t2EORrr:
case ARM::t2EORri: { case ARM::t2EORri: {
// Scan forward for the use of CPSR, if it's a conditional code requires // Scan forward for the use of CPSR
// When checking against MI: if it's a conditional code requires
// checking of V bit, then this is not safe to do. If we can't find the // checking of V bit, then this is not safe to do. If we can't find the
// CPSR use (i.e. used in another block), then it's not safe to perform // CPSR use (i.e. used in another block), then it's not safe to perform
// the optimization. // the optimization.
// When checking against Sub, we handle the condition codes GE, LT, GT, LE.
SmallVector<MachineOperand*, 4> OperandsToUpdate;
bool isSafe = false; bool isSafe = false;
I = CmpInstr; I = CmpInstr;
E = MI->getParent()->end(); E = CmpInstr->getParent()->end();
while (!isSafe && ++I != E) { while (!isSafe && ++I != E) {
const MachineInstr &Instr = *I; const MachineInstr &Instr = *I;
for (unsigned IO = 0, EO = Instr.getNumOperands(); for (unsigned IO = 0, EO = Instr.getNumOperands();
@ -1918,28 +1973,65 @@ OptimizeCompareInstr(MachineInstr *CmpInstr, unsigned SrcReg, int CmpMask,
} }
// Condition code is after the operand before CPSR. // Condition code is after the operand before CPSR.
ARMCC::CondCodes CC = (ARMCC::CondCodes)Instr.getOperand(IO-1).getImm(); ARMCC::CondCodes CC = (ARMCC::CondCodes)Instr.getOperand(IO-1).getImm();
switch (CC) { if (Sub)
default: switch (CC) {
isSafe = true; default:
break; return false;
case ARMCC::VS: case ARMCC::GE:
case ARMCC::VC: case ARMCC::LT:
case ARMCC::GE: case ARMCC::GT:
case ARMCC::LT: case ARMCC::LE:
case ARMCC::GT: // If we have SUB(r1, r2) and CMP(r2, r1), the condition code based
case ARMCC::LE: // on CMP needs to be updated to be based on SUB.
return false; // Push the condition code operands to OperandsToUpdate.
} // If it is safe to remove CmpInstr, the condition code of these
// operands will be modified.
if (SrcReg2 != 0 && Sub->getOperand(1).getReg() == SrcReg2 &&
Sub->getOperand(2).getReg() == SrcReg)
OperandsToUpdate.push_back(&((*I).getOperand(IO-1)));
break;
}
else
switch (CC) {
default:
isSafe = true;
break;
case ARMCC::VS:
case ARMCC::VC:
case ARMCC::GE:
case ARMCC::LT:
case ARMCC::GT:
case ARMCC::LE:
return false;
}
} }
} }
if (!isSafe) // If the candidate is Sub, we may exit the loop at end of the basic block.
// In that case, it is still safe to remove CmpInstr.
if (!isSafe && !Sub)
return false; return false;
// Toggle the optional operand to CPSR. // Toggle the optional operand to CPSR.
MI->getOperand(5).setReg(ARM::CPSR); MI->getOperand(5).setReg(ARM::CPSR);
MI->getOperand(5).setIsDef(true); MI->getOperand(5).setIsDef(true);
CmpInstr->eraseFromParent(); CmpInstr->eraseFromParent();
// Modify the condition code of operands in OperandsToUpdate.
// Since we have SUB(r1, r2) and CMP(r2, r1), the condition code needs to
// be changed from r2 > r1 to r1 < r2, from r2 < r1 to r1 > r2, etc.
for (unsigned i = 0; i < OperandsToUpdate.size(); i++) {
ARMCC::CondCodes CC = (ARMCC::CondCodes)OperandsToUpdate[i]->getImm();
ARMCC::CondCodes NewCC;
switch(CC) {
default: break;
case ARMCC::GE: NewCC = ARMCC::LE; break;
case ARMCC::LT: NewCC = ARMCC::GT; break;
case ARMCC::GT: NewCC = ARMCC::LT; break;
case ARMCC::LE: NewCC = ARMCC::GT; break;
}
OperandsToUpdate[i]->setImm(NewCC);
}
return true; return true;
} }
} }

View File

@ -0,0 +1,34 @@
; RUN: llc < %s -mtriple=arm-apple-darwin | FileCheck %s
define i32 @f(i32 %a, i32 %b) nounwind ssp {
entry:
; CHECK: f:
; CHECK: subs
; CHECK-NOT: cmp
%cmp = icmp sgt i32 %a, %b
%sub = sub nsw i32 %a, %b
%sub. = select i1 %cmp, i32 %sub, i32 0
ret i32 %sub.
}
define i32 @g(i32 %a, i32 %b) nounwind ssp {
entry:
; CHECK: g:
; CHECK: subs
; CHECK-NOT: cmp
%cmp = icmp slt i32 %a, %b
%sub = sub nsw i32 %b, %a
%sub. = select i1 %cmp, i32 %sub, i32 0
ret i32 %sub.
}
define i32 @h(i32 %a, i32 %b) nounwind ssp {
entry:
; CHECK: h:
; CHECK: subs
; CHECK-NOT: cmp
%cmp = icmp sgt i32 %a, 3
%sub = sub nsw i32 %a, 3
%sub. = select i1 %cmp, i32 %sub, i32 %b
ret i32 %sub.
}