[llvm-commits] [llvm] r157831 - in /llvm/trunk: lib/Target/X86/X86InstrArithmetic.td lib/Target/X86/X86InstrInfo.cpp lib/Target/X86/X86InstrInfo.h test/CodeGen/X86/jump_sign.ll
Manman Ren
mren at apple.com
Sat Jun 2 20:16:21 PDT 2012
This patch is now reverted.
Thanks for your feedback.
Manman
On Jun 2, 2012, at 3:55 PM, Chandler Carruth wrote:
>
> On Fri, Jun 1, 2012 at 12:49 PM, Manman Ren <mren at apple.com> wrote:
> >
> > Author: mren
> > Date: Fri Jun 1 14:49:33 2012
> > New Revision: 157831
> >
> > URL: http://llvm.org/viewvc/llvm-project?rev=157831&view=rev
> > Log:
> > X86: peephole optimization to remove cmp instruction
>
> I'm frustrated that you waited a total of 3 hours for review on the final version of this patch before committing it, w/o getting an LGTM. Eric even made comments on that thread, which he has had to repeat here. Please try to give the code review process a chance.
> This patch doesn't feel ready for commit:
>
> 1) From my original comments: I still think the properties of instructions you're currently hard coding in C++ need to be modeled in a more principled manner. Maybe this isn't possible, I'm not a backend expert, but in code review all you said was that it didn't exist today. The point of my comment was that if these properties are not currently available as a fundamental part of the instruction, you should add them rather than writing one-off functions like this.
>
> 2) You haven't followed the coding conventions or addressed any style issues with the patch. Nor have you added doxygen comments for the APIs you've adding. I'll try to mention a few of the style issues below, but I'm just pointing out a few. It would be good to go over this and try to be consistent.
>
> 3) I still think that this is a bit of a hack to handle a single case of a more general problem. There are numerous instructions in x86 that set some subset of EFLAGS. We should have a general pass that can both re-use existing instructions' flags, and even switch instructions which have equivalent instructions (functionally) that additionally set flags. Certainly, 'cmp x, y' sets flags *differently* from binary operations other than 'sub x, y', but you're already handling cases like x and y being reversed, so it doesn't seem like a huge leap here.
>
> 4) Also, what about removing 'test' as well as 'cmp'?
>
> >
> > This patch will optimize the following:
> > sub r1, r3
> > cmp r3, r1 or cmp r1, r3
> > bge L1
> > TO
> > sub r1, r3
> > bge L1 or ble L1
> >
> > If the branch instruction can use flag from "sub", then we can eliminate
> > the "cmp" instruction.
> >
> > Modified:
> > llvm/trunk/lib/Target/X86/X86InstrArithmetic.td
> > llvm/trunk/lib/Target/X86/X86InstrInfo.cpp
> > llvm/trunk/lib/Target/X86/X86InstrInfo.h
> > llvm/trunk/test/CodeGen/X86/jump_sign.ll
> >
> > Modified: llvm/trunk/lib/Target/X86/X86InstrArithmetic.td
> > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86InstrArithmetic.td?rev=157831&r1=157830&r2=157831&view=diff
> > ==============================================================================
> > --- llvm/trunk/lib/Target/X86/X86InstrArithmetic.td (original)
> > +++ llvm/trunk/lib/Target/X86/X86InstrArithmetic.td Fri Jun 1 14:49:33 2012
> > @@ -1143,7 +1143,9 @@
> > 0, 0>;
> > }
> >
> > +let isCompare = 1 in {
> > defm CMP : ArithBinOp_F<0x38, 0x3A, 0x3C, "cmp", MRM7r, MRM7m, X86cmp, 0, 0>;
> > +}
> >
> >
> > //===----------------------------------------------------------------------===//
> >
> > Modified: llvm/trunk/lib/Target/X86/X86InstrInfo.cpp
> > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86InstrInfo.cpp?rev=157831&r1=157830&r2=157831&view=diff
> > ==============================================================================
> > --- llvm/trunk/lib/Target/X86/X86InstrInfo.cpp (original)
> > +++ llvm/trunk/lib/Target/X86/X86InstrInfo.cpp Fri Jun 1 14:49:33 2012
> > @@ -33,6 +33,7 @@
> > #include "llvm/Support/ErrorHandling.h"
> > #include "llvm/Support/raw_ostream.h"
> > #include "llvm/Target/TargetOptions.h"
> > +#include "llvm/ADT/Statistic.h"
> > #include <limits>
> >
> > #define GET_INSTRINFO_CTOR
> > @@ -40,6 +41,8 @@
> >
> > using namespace llvm;
> >
> > +STATISTIC(NumCmpsRemoved, "Number of Cmps removed due to an earlier Sub");
> > +
> > static cl::opt<bool>
> > NoFusing("disable-spill-fusing",
> > cl::desc("Disable fusing of spill code into instructions"));
> > @@ -2728,6 +2731,326 @@
> > }
> >
> > bool X86InstrInfo::
> > +AnalyzeCompare(const MachineInstr *MI, unsigned &SrcReg, int &CmpMask,
> > + int &CmpValue) const {
>
> 'analyzeCompare'
>
> >
> > + switch (MI->getOpcode()) {
> > + default: break;
> > + case X86::CMP64ri32:
> > + case X86::CMP64ri8:
> > + case X86::CMP32ri:
> > + case X86::CMP32ri8:
> > + case X86::CMP16ri:
> > + case X86::CMP16ri8:
> > + case X86::CMP8ri:
> > + SrcReg = MI->getOperand(0).getReg();
> > + CmpMask = ~0;
> > + CmpValue = MI->getOperand(1).getImm();
> > + return true;
> > + case X86::CMP64rr:
> > + case X86::CMP32rr:
> > + case X86::CMP16rr:
> > + case X86::CMP8rr:
> > + SrcReg = MI->getOperand(0).getReg();
> > + CmpMask = ~0;
> > + CmpValue = 0;
> > + return true;
> > + }
> > +
> > + return false;
> > +}
> > +
> > +// This function updates condition code for SET Opcodes.
> > +// The input condition code can be E,NE,L,LE,G,GE,B,BE,A,AE and
> > +// the updated condition code will be E,NE,G,GE,L,LE,A,AE,B,BE.
> > +// This is to convert from a > b to b < a, a >= b to b <= a etc.
> > +static unsigned UpdateSETCondToOptimizeCmp(unsigned SETOpc) {
>
> Update... -> update...
>
> >
> > + switch (SETOpc) {
> > + default: return 0;
> > + case X86::SETEr: return X86::SETEr;
> > + case X86::SETEm: return X86::SETEm;
> > + case X86::SETNEr: return X86::SETNEr;
> > + case X86::SETNEm: return X86::SETNEm;
> > + case X86::SETLr: return X86::SETGr;
> > + case X86::SETLm: return X86::SETGm;
> > + case X86::SETLEr: return X86::SETGEr;
> > + case X86::SETLEm: return X86::SETGEm;
> > + case X86::SETGr: return X86::SETLr;
> > + case X86::SETGm: return X86::SETLm;
> > + case X86::SETGEr: return X86::SETLEr;
> > + case X86::SETGEm: return X86::SETLEm;
> > + case X86::SETBr: return X86::SETAr;
> > + case X86::SETBm: return X86::SETAm;
> > + case X86::SETBEr: return X86::SETAEr;
> > + case X86::SETBEm: return X86::SETAEm;
> > + case X86::SETAr: return X86::SETBr;
> > + case X86::SETAm: return X86::SETBm;
> > + case X86::SETAEr: return X86::SETBEr;
> > + case X86::SETAEm: return X86::SETBEm;
> > + }
> > +}
> > +
> > +// This function updates condition code for Branch Opcodes.
> > +// The input condition code can be E,NE,L,LE,G,GE,B,BE,A,AE and
> > +// the updated condition code will be E,NE,G,GE,L,LE,A,AE,B,BE.
> > +// This is to convert from a > b to b < a, a >= b to b <= a etc.
> > +static unsigned UpdateBranchCondToOptimizeCmp(unsigned BranchOpc) {
>
> Update -> update
>
> >
> > + switch (BranchOpc) {
> > + default: return 0;
> > + case X86::JE_4: return X86::JE_4;
> > + case X86::JNE_4: return X86::JNE_4;
> > + case X86::JL_4: return X86::JG_4;
> > + case X86::JLE_4: return X86::JGE_4;
> > + case X86::JG_4: return X86::JL_4;
> > + case X86::JGE_4: return X86::JLE_4;
> > + case X86::JB_4: return X86::JA_4;
> > + case X86::JBE_4: return X86::JAE_4;
> > + case X86::JA_4: return X86::JB_4;
> > + case X86::JAE_4: return X86::JBE_4;
> > + }
> > +}
> > +
> > +// This function updates condition code for CMOV Opcodes.
> > +// The input condition code can be E,NE,L,LE,G,GE,B,BE,A,AE and
> > +// the updated condition code will be E,NE,G,GE,L,LE,A,AE,B,BE.
> > +// This is to convert from a > b to b < a, a >= b to b <= a etc.
> > +static unsigned UpdateCMovCondToOptimizeCmp(unsigned CMovOpc) {
> > + switch (CMovOpc) {
> > + default: return 0;
> > + case X86::CMOVE16rm: return X86::CMOVE16rm;
> > + case X86::CMOVE16rr: return X86::CMOVE16rr;
> > + case X86::CMOVE32rm: return X86::CMOVE32rm;
> > + case X86::CMOVE32rr: return X86::CMOVE32rr;
> > + case X86::CMOVE64rm: return X86::CMOVE64rm;
> > + case X86::CMOVE64rr: return X86::CMOVE64rr;
> > + case X86::CMOVNE16rm: return X86::CMOVNE16rm;
> > + case X86::CMOVNE16rr: return X86::CMOVNE16rr;
> > + case X86::CMOVNE32rm: return X86::CMOVNE32rm;
> > + case X86::CMOVNE32rr: return X86::CMOVNE32rr;
> > + case X86::CMOVNE64rm: return X86::CMOVNE64rm;
> > + case X86::CMOVNE64rr: return X86::CMOVNE64rr;
> > +
> > + case X86::CMOVL16rm: return X86::CMOVG16rm;
> > + case X86::CMOVL16rr: return X86::CMOVG16rr;
> > + case X86::CMOVL32rm: return X86::CMOVG32rm;
> > + case X86::CMOVL32rr: return X86::CMOVG32rr;
> > + case X86::CMOVL64rm: return X86::CMOVG64rm;
> > + case X86::CMOVL64rr: return X86::CMOVG64rr;
> > + case X86::CMOVLE16rm: return X86::CMOVGE16rm;
> > + case X86::CMOVLE16rr: return X86::CMOVGE16rr;
> > + case X86::CMOVLE32rm: return X86::CMOVGE32rm;
> > + case X86::CMOVLE32rr: return X86::CMOVGE32rr;
> > + case X86::CMOVLE64rm: return X86::CMOVGE64rm;
> > + case X86::CMOVLE64rr: return X86::CMOVGE64rr;
> > +
> > + case X86::CMOVG16rm: return X86::CMOVL16rm;
> > + case X86::CMOVG16rr: return X86::CMOVL16rr;
> > + case X86::CMOVG32rm: return X86::CMOVL32rm;
> > + case X86::CMOVG32rr: return X86::CMOVL32rr;
> > + case X86::CMOVG64rm: return X86::CMOVL64rm;
> > + case X86::CMOVG64rr: return X86::CMOVL64rr;
> > + case X86::CMOVGE16rm: return X86::CMOVLE16rm;
> > + case X86::CMOVGE16rr: return X86::CMOVLE16rr;
> > + case X86::CMOVGE32rm: return X86::CMOVLE32rm;
> > + case X86::CMOVGE32rr: return X86::CMOVLE32rr;
> > + case X86::CMOVGE64rm: return X86::CMOVLE64rm;
> > + case X86::CMOVGE64rr: return X86::CMOVLE64rr;
> > +
> > + case X86::CMOVB16rm: return X86::CMOVA16rm;
> > + case X86::CMOVB16rr: return X86::CMOVA16rr;
> > + case X86::CMOVB32rm: return X86::CMOVA32rm;
> > + case X86::CMOVB32rr: return X86::CMOVA32rr;
> > + case X86::CMOVB64rm: return X86::CMOVA64rm;
> > + case X86::CMOVB64rr: return X86::CMOVA64rr;
> > + case X86::CMOVBE16rm: return X86::CMOVAE16rm;
> > + case X86::CMOVBE16rr: return X86::CMOVAE16rr;
> > + case X86::CMOVBE32rm: return X86::CMOVAE32rm;
> > + case X86::CMOVBE32rr: return X86::CMOVAE32rr;
> > + case X86::CMOVBE64rm: return X86::CMOVAE64rm;
> > + case X86::CMOVBE64rr: return X86::CMOVAE64rr;
> > +
> > + case X86::CMOVA16rm: return X86::CMOVB16rm;
> > + case X86::CMOVA16rr: return X86::CMOVB16rr;
> > + case X86::CMOVA32rm: return X86::CMOVB32rm;
> > + case X86::CMOVA32rr: return X86::CMOVB32rr;
> > + case X86::CMOVA64rm: return X86::CMOVB64rm;
> > + case X86::CMOVA64rr: return X86::CMOVB64rr;
> > + case X86::CMOVAE16rm: return X86::CMOVBE16rm;
> > + case X86::CMOVAE16rr: return X86::CMOVBE16rr;
> > + case X86::CMOVAE32rm: return X86::CMOVBE32rm;
> > + case X86::CMOVAE32rr: return X86::CMOVBE32rr;
> > + case X86::CMOVAE64rm: return X86::CMOVBE64rm;
> > + case X86::CMOVAE64rr: return X86::CMOVBE64rr;
> > + }
> > +}
> > +
> > +bool X86InstrInfo::
> > +OptimizeCompareInstr(MachineInstr *CmpInstr, unsigned SrcReg, int CmpMask,
>
> Optimize -> optimize
>
> >
> > + int CmpValue, const MachineRegisterInfo *MRI) const {
> > + MachineRegisterInfo::def_iterator DI = MRI->def_begin(SrcReg);
> > + if (llvm::next(DI) != MRI->def_end())
> > + // Only support one definition.
> > + return false;
> > +
> > + MachineInstr *MI = &*DI;
> > + // Get ready to iterate backward from CmpInstr.
> > + MachineBasicBlock::iterator I = CmpInstr, E = MI,
> > + B = CmpInstr->getParent()->begin();
>
> Reverse iterators please. Iterating backwards is too hard to follow otherwise. Add the iterators if they're missing.
>
> >
> > +
> > + // Early exit if CmpInstr is at the beginning of the BB.
> > + if (I == B) return false;
>
> Set up your loop variables below, where you're looping. You shouldn't need to do early exits etc, the loop simply won't iterate...
>
> >
> > +
> > + // 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() == X86::CMP64rr ||
> > + CmpInstr->getOpcode() == X86::CMP32rr ||
> > + CmpInstr->getOpcode() == X86::CMP16rr ||
> > + CmpInstr->getOpcode() == X86::CMP8rr) {
> > + SrcReg2 = CmpInstr->getOperand(1).getReg();
> > + }
> > +
> > + // Search backwards for a SUB instruction.
> > + // If EFLAGS is updated in the middle, we can not remove the CMP instruction.
> > + --I;
> > + for (; I != E; --I) {
> > + const MachineInstr &Instr = *I;
> > +
> > + // Check whether the current instruction is SUB(r1, r2) or SUB(r2, r1).
> > + if (((CmpInstr->getOpcode() == X86::CMP64rr &&
> > + Instr.getOpcode() == X86::SUB64rr) ||
> > + (CmpInstr->getOpcode() == X86::CMP32rr &&
> > + Instr.getOpcode() == X86::SUB32rr)||
> > + (CmpInstr->getOpcode() == X86::CMP16rr &&
> > + Instr.getOpcode() == X86::SUB16rr)||
> > + (CmpInstr->getOpcode() == X86::CMP8rr &&
> > + Instr.getOpcode() == X86::SUB8rr)) &&
> > + ((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() == X86::CMP64ri32 &&
> > + Instr.getOpcode() == X86::SUB64ri32) ||
> > + (CmpInstr->getOpcode() == X86::CMP64ri8 &&
> > + Instr.getOpcode() == X86::SUB64ri8) ||
> > + (CmpInstr->getOpcode() == X86::CMP32ri &&
> > + Instr.getOpcode() == X86::SUB32ri) ||
> > + (CmpInstr->getOpcode() == X86::CMP32ri8 &&
> > + Instr.getOpcode() == X86::SUB32ri8) ||
> > + (CmpInstr->getOpcode() == X86::CMP16ri &&
> > + Instr.getOpcode() == X86::SUB16ri) ||
> > + (CmpInstr->getOpcode() == X86::CMP16ri8 &&
> > + Instr.getOpcode() == X86::SUB16ri8) ||
> > + (CmpInstr->getOpcode() == X86::CMP8ri &&
> > + Instr.getOpcode() == X86::SUB8ri)) &&
> > + CmpValue != 0 &&
> > + Instr.getOperand(1).getReg() == SrcReg &&
> > + Instr.getOperand(2).getImm() == CmpValue) {
> > + Sub = &*I;
> > + break;
> > + }
> > +
> > + for (unsigned IO = 0, EO = Instr.getNumOperands(); IO != EO; ++IO) {
> > + const MachineOperand &MO = Instr.getOperand(IO);
> > + if (MO.isRegMask() && MO.clobbersPhysReg(X86::EFLAGS))
> > + return false;
> > + if (!MO.isReg()) continue;
> > +
> > + // This instruction modifies or uses EFLAGS before we find a SUB.
> > + // We can't do this transformation.
> > + if (MO.getReg() == X86::EFLAGS)
> > + return false;
> > + }
>
> Please hoist this loop into a helper function. Ideally on MachineInstr so others can use it. It seems generically useful.
>
> >
> > +
> > + if (I == B)
> > + // Reaching beginning of the block.
> > + return false;
> > + }
> > +
> > + // Return false if no candidates exist.
> > + if (!Sub)
> > + return false;
> > + MI = Sub;
> > +
> > + switch (MI->getOpcode()) {
> > + default: break;
> > + case X86::SUB64rr:
> > + case X86::SUB32rr:
> > + case X86::SUB16rr:
> > + case X86::SUB8rr:
> > + case X86::SUB64ri32:
> > + case X86::SUB64ri8:
> > + case X86::SUB32ri:
> > + case X86::SUB32ri8:
> > + case X86::SUB16ri:
> > + case X86::SUB16ri8:
> > + case X86::SUB8ri: {
> > + // Scan forward from CmpInstr for the use of EFLAGS.
> > + // Handle the condition codes GE, L, G, LE, B, L, BE, LE.
> > + SmallVector<std::pair<MachineInstr*, unsigned /*NewOpc*/>, 4> OpsToUpdate;
> > + bool isSafe = false;
>
> isSafe -> IsSafe.
>
> > + I = CmpInstr;
> > + E = CmpInstr->getParent()->end();
> > + while (!isSafe && ++I != E) {
>
> Don't re-use loop variables this way. It's much better to declare them in the for (...) loop they are used for, and declare new ones in each loop.
>
> > + const MachineInstr &Instr = *I;
> > + for (unsigned IO = 0, EO = Instr.getNumOperands();
> > + !isSafe && IO != EO; ++IO) {
> > + const MachineOperand &MO = Instr.getOperand(IO);
> > + if (MO.isRegMask() && MO.clobbersPhysReg(X86::EFLAGS)) {
> > + isSafe = true;
> > + break;
>
> This whole thing would be a lot more clear if you hoisted this into a helper function and used early exit.
>
> > + }
> > + if (!MO.isReg() || MO.getReg() != X86::EFLAGS)
> > + continue;
> > + // EFLAGS is redefined by this instruction.
> > + if (MO.isDef()) {
> > + isSafe = true;
> > + break;
> > + }
> > + // EFLAGS is used by this instruction.
> > +
> > + // If 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.
> > + unsigned NewOpc = UpdateBranchCondToOptimizeCmp(Instr.getOpcode());
> > + if (!NewOpc) NewOpc = UpdateSETCondToOptimizeCmp(Instr.getOpcode());
> > + if (!NewOpc) NewOpc = UpdateCMovCondToOptimizeCmp(Instr.getOpcode());
> > + if (!NewOpc) return false;
> > +
> > + // Push the MachineInstr to OpsToUpdate.
> > + // If it is safe to remove CmpInstr, the condition code of these
> > + // instructions will be modified.
> > + if (SrcReg2 != 0 && Sub->getOperand(1).getReg() == SrcReg2 &&
> > + Sub->getOperand(2).getReg() == SrcReg)
> > + OpsToUpdate.push_back(std::make_pair(&*I, NewOpc));
> > + }
> > + }
> > +
> > + // We may exit the loop at end of the basic block.
> > + // In that case, it is still safe to remove CmpInstr.
> > +
> > + // Make sure Sub instruction defines EFLAGS.
> > + assert(MI->getOperand(3).getReg() == X86::EFLAGS &&
> > + "Expected EFLAGS is the 4th operand of SUBrr or SUBri.");
> > + MI->getOperand(3).setIsDef(true);
> > + CmpInstr->eraseFromParent();
> > +
> > + // Modify the condition code of instructions in OpsToUpdate.
> > + for (unsigned i = 0; i < OpsToUpdate.size(); i++)
>
> Always cache the end value in a loop variable.
>
>
> > + OpsToUpdate[i].first->setDesc(get(OpsToUpdate[i].second));
> > + NumCmpsRemoved++;
> > + return true;
> > + }
> > + }
> > +
> > + return false;
> > +}
> > +
> > +bool X86InstrInfo::
> > OptimizeSubInstr(MachineInstr *SubInstr, const MachineRegisterInfo *MRI) const {
> > // If destination is a memory operand, do not perform this optimization.
> > if ((SubInstr->getOpcode() != X86::SUB64rr) &&
> >
> > Modified: llvm/trunk/lib/Target/X86/X86InstrInfo.h
> > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/X86/X86InstrInfo.h?rev=157831&r1=157830&r2=157831&view=diff
> > ==============================================================================
> > --- llvm/trunk/lib/Target/X86/X86InstrInfo.h (original)
> > +++ llvm/trunk/lib/Target/X86/X86InstrInfo.h Fri Jun 1 14:49:33 2012
> > @@ -367,6 +367,12 @@
> > virtual bool OptimizeSubInstr(MachineInstr *SubInstr,
> > const MachineRegisterInfo *MRI) const;
> >
> > + virtual bool AnalyzeCompare(const MachineInstr *MI, unsigned &SrcReg,
> > + int &CmpMask, int &CmpValue) const;
> > + virtual bool OptimizeCompareInstr(MachineInstr *CmpInstr, unsigned SrcReg,
> > + int CmpMask, int CmpValue,
> > + const MachineRegisterInfo *MRI) const;
> > +
> > private:
> > MachineInstr * convertToThreeAddressWithLEA(unsigned MIOpc,
> > MachineFunction::iterator &MFI,
> >
> > Modified: llvm/trunk/test/CodeGen/X86/jump_sign.ll
> > URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/jump_sign.ll?rev=157831&r1=157830&r2=157831&view=diff
> > ==============================================================================
> > --- llvm/trunk/test/CodeGen/X86/jump_sign.ll (original)
> > +++ llvm/trunk/test/CodeGen/X86/jump_sign.ll Fri Jun 1 14:49:33 2012
> > @@ -83,6 +83,25 @@
> > %cond = select i1 %cmp, i32 %sub, i32 0
> > ret i32 %cond
> > }
> > +; redundant cmp instruction
> > +define i32 @l(i32 %a, i32 %b) nounwind {
> > +entry:
> > +; CHECK: l:
> > +; CHECK-NOT: cmp
> > + %cmp = icmp slt i32 %b, %a
> > + %sub = sub nsw i32 %a, %b
> > + %cond = select i1 %cmp, i32 %sub, i32 %a
> > + ret i32 %cond
> > +}
> > +define i32 @m(i32 %a, i32 %b) nounwind {
> > +entry:
> > +; CHECK: m:
> > +; CHECK-NOT: cmp
> > + %cmp = icmp sgt i32 %a, %b
> > + %sub = sub nsw i32 %a, %b
> > + %cond = select i1 %cmp, i32 %b, i32 %sub
> > + ret i32 %cond
> > +}
> > ; rdar://11540023
> > define i64 @n(i64 %x, i64 %y) nounwind {
> > entry:
> >
> >
> > _______________________________________________
> > llvm-commits mailing list
> > llvm-commits at cs.uiuc.edu
> > http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20120602/6aa9c7cb/attachment.html>
More information about the llvm-commits
mailing list