[llvm-commits] [llvm] r156599 - in /llvm/trunk: lib/CodeGen/PeepholeOptimizer.cpp lib/Target/ARM/ARMBaseInstrInfo.cpp test/CodeGen/ARM/sub-cmp-peephole.ll

David Blaikie dblaikie at gmail.com
Mon May 14 14:53:16 PDT 2012


On Thu, May 10, 2012 at 6:30 PM, Manman Ren <mren at apple.com> wrote:
> Author: mren
> Date: Thu May 10 20:30:47 2012
> New Revision: 156599
>
> URL: http://llvm.org/viewvc/llvm-project?rev=156599&view=rev
> Log:
> 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
>
> Added:
>    llvm/trunk/test/CodeGen/ARM/sub-cmp-peephole.ll
> Modified:
>    llvm/trunk/lib/CodeGen/PeepholeOptimizer.cpp
>    llvm/trunk/lib/Target/ARM/ARMBaseInstrInfo.cpp
>
> Modified: llvm/trunk/lib/CodeGen/PeepholeOptimizer.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/PeepholeOptimizer.cpp?rev=156599&r1=156598&r2=156599&view=diff
> ==============================================================================
> --- llvm/trunk/lib/CodeGen/PeepholeOptimizer.cpp (original)
> +++ llvm/trunk/lib/CodeGen/PeepholeOptimizer.cpp Thu May 10 20:30:47 2012
> @@ -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
>
> Modified: llvm/trunk/lib/Target/ARM/ARMBaseInstrInfo.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMBaseInstrInfo.cpp?rev=156599&r1=156598&r2=156599&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Target/ARM/ARMBaseInstrInfo.cpp (original)
> +++ llvm/trunk/lib/Target/ARM/ARMBaseInstrInfo.cpp Thu May 10 20:30:47 2012
> @@ -1753,6 +1753,12 @@
>     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 @@
>  }
>
>  /// 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 @@
>     }
>   }
>
> -  // 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 @@
>         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 @@
>   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<MachineOperand*, 4> 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 @@
>         }
>         // 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;

I changed this break to an llvm_unreachable in r156780 since, if it
was reached, you would be calling setImm with an uninitialized
variable after the switch. If that was wrong/there should be some
other solution to this (perhaps you want to call setImm anyway & know
that it won't be accessed later on, or in the default case you do want
to initialize newCC to some specific value) let me know and/or commit
the change yourself.

(found by GCC's maybe-uninitialized warning, which isn't great - but
sometimes points in the right direction)

Thanks,
- David

> +      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;
>   }
>   }
>
> Added: llvm/trunk/test/CodeGen/ARM/sub-cmp-peephole.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/ARM/sub-cmp-peephole.ll?rev=156599&view=auto
> ==============================================================================
> --- llvm/trunk/test/CodeGen/ARM/sub-cmp-peephole.ll (added)
> +++ llvm/trunk/test/CodeGen/ARM/sub-cmp-peephole.ll Thu May 10 20:30:47 2012
> @@ -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.
> +}
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits




More information about the llvm-commits mailing list