diff --git a/lib/CodeGen/PeepholeOptimizer.cpp b/lib/CodeGen/PeepholeOptimizer.cpp index 70b5020f541..ab672c9c585 100644 --- a/lib/CodeGen/PeepholeOptimizer.cpp +++ b/lib/CodeGen/PeepholeOptimizer.cpp @@ -31,6 +31,15 @@ // same flag that the "cmp" instruction sets and that "bz" uses, then we can // 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: // // v1 = bitcast v0 diff --git a/lib/Target/ARM/ARMBaseInstrInfo.cpp b/lib/Target/ARM/ARMBaseInstrInfo.cpp index c6280f819a4..d0ac23f3f87 100644 --- a/lib/Target/ARM/ARMBaseInstrInfo.cpp +++ b/lib/Target/ARM/ARMBaseInstrInfo.cpp @@ -1753,6 +1753,12 @@ AnalyzeCompare(const MachineInstr *MI, unsigned &SrcReg, int &CmpMask, CmpMask = ~0; CmpValue = MI->getOperand(1).getImm(); return true; + case ARM::CMPrr: + case ARM::t2CMPrr: + SrcReg = MI->getOperand(0).getReg(); + CmpMask = ~0; + CmpValue = 0; + return true; case ARM::TSTri: case ARM::t2TSTri: 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 -/// 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:: OptimizeCompareInstr(MachineInstr *CmpInstr, unsigned SrcReg, int CmpMask, int CmpValue, const MachineRegisterInfo *MRI) const { - if (CmpValue != 0) - return false; MachineRegisterInfo::def_iterator DI = MRI->def_begin(SrcReg); 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 - // as the comparison. - if (MI->getParent() != CmpInstr->getParent()) - 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(); + // Get ready to iterate backward from CmpInstr. + MachineBasicBlock::iterator I = CmpInstr, E = MI, + B = CmpInstr->getParent()->begin(); // Early exit if CmpInstr is at the beginning of the BB. 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; for (; I != E; --I) { const MachineInstr &Instr = *I; @@ -1853,12 +1879,38 @@ OptimizeCompareInstr(MachineInstr *CmpInstr, unsigned SrcReg, int CmpMask, 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) // The 'and' is below the comparison instruction. 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()) { default: break; case ARM::RSBrr: @@ -1894,13 +1946,16 @@ OptimizeCompareInstr(MachineInstr *CmpInstr, unsigned SrcReg, int CmpMask, case ARM::EORri: case ARM::t2EORrr: 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 // CPSR use (i.e. used in another block), then it's not safe to perform // the optimization. + // When checking against Sub, we handle the condition codes GE, LT, GT, LE. + SmallVector OperandsToUpdate; bool isSafe = false; I = CmpInstr; - E = MI->getParent()->end(); + E = CmpInstr->getParent()->end(); while (!isSafe && ++I != E) { const MachineInstr &Instr = *I; 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. ARMCC::CondCodes CC = (ARMCC::CondCodes)Instr.getOperand(IO-1).getImm(); - 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 (Sub) + switch (CC) { + default: + return false; + case ARMCC::GE: + case ARMCC::LT: + case ARMCC::GT: + case ARMCC::LE: + // If we have SUB(r1, r2) and CMP(r2, r1), the condition code based + // on CMP needs to be updated to be based on SUB. + // 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; // Toggle the optional operand to CPSR. MI->getOperand(5).setReg(ARM::CPSR); MI->getOperand(5).setIsDef(true); 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; } } diff --git a/test/CodeGen/ARM/sub-cmp-peephole.ll b/test/CodeGen/ARM/sub-cmp-peephole.ll new file mode 100644 index 00000000000..e0970f3ebdc --- /dev/null +++ b/test/CodeGen/ARM/sub-cmp-peephole.ll @@ -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. +}