mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-11-02 07:11:49 +00:00
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:
parent
d4347e1af9
commit
247c5ab07c
@ -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
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
34
test/CodeGen/ARM/sub-cmp-peephole.ll
Normal file
34
test/CodeGen/ARM/sub-cmp-peephole.ll
Normal 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.
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user