diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp index 660a1bd0bdf..8005e239ddf 100644 --- a/lib/Target/X86/X86ISelLowering.cpp +++ b/lib/Target/X86/X86ISelLowering.cpp @@ -8573,6 +8573,46 @@ SDValue X86TargetLowering::LowerSELECT(SDValue Op, SelectionDAG &DAG) const { Cond = NewCond; } + // Handle the following cases related to max and min: + // (a > b) ? (a-b) : 0 + // (a >= b) ? (a-b) : 0 + // (b < a) ? (a-b) : 0 + // (b <= a) ? (a-b) : 0 + // Comparison is removed to use EFLAGS from SUB. + if (ConstantSDNode *C = dyn_cast(Op2)) + if (Cond.getOpcode() == X86ISD::SETCC && + Cond.getOperand(1).getOpcode() == X86ISD::CMP && + (Op1.getOpcode() == ISD::SUB || Op1.getOpcode() == X86ISD::SUB) && + C->getAPIntValue() == 0) { + SDValue Cmp = Cond.getOperand(1); + unsigned CC = cast(Cond.getOperand(0))->getZExtValue(); + if ((DAG.isEqualTo(Op1.getOperand(0), Cmp.getOperand(0)) && + DAG.isEqualTo(Op1.getOperand(1), Cmp.getOperand(1)) && + (CC == X86::COND_G || CC == X86::COND_GE || + CC == X86::COND_A || CC == X86::COND_AE)) || + (DAG.isEqualTo(Op1.getOperand(0), Cmp.getOperand(1)) && + DAG.isEqualTo(Op1.getOperand(1), Cmp.getOperand(0)) && + (CC == X86::COND_L || CC == X86::COND_LE || + CC == X86::COND_B || CC == X86::COND_BE))) { + + if (Op1.getOpcode() == ISD::SUB) { + SDVTList VTs = DAG.getVTList(Op1.getValueType(), MVT::i32); + SDValue New = DAG.getNode(X86ISD::SUB, DL, VTs, + Op1.getOperand(0), Op1.getOperand(1)); + DAG.ReplaceAllUsesWith(Op1, New); + Op1 = New; + } + + SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::Glue); + unsigned NewCC = (CC == X86::COND_G || CC == X86::COND_GE || + CC == X86::COND_L || + CC == X86::COND_LE) ? X86::COND_GE : X86::COND_AE; + SDValue Ops[] = { Op2, Op1, DAG.getConstant(NewCC, MVT::i8), + SDValue(Op1.getNode(), 1) }; + return DAG.getNode(X86ISD::CMOV, DL, VTs, Ops, array_lengthof(Ops)); + } + } + // (select (x == 0), -1, y) -> (sign_bit (x - 1)) | y // (select (x == 0), y, -1) -> ~(sign_bit (x - 1)) | y // (select (x != 0), y, -1) -> (sign_bit (x - 1)) | y diff --git a/test/CodeGen/X86/jump_sign.ll b/test/CodeGen/X86/jump_sign.ll index dbd133cd9ab..35f69c95683 100644 --- a/test/CodeGen/X86/jump_sign.ll +++ b/test/CodeGen/X86/jump_sign.ll @@ -32,3 +32,45 @@ entry: %cond = select i1 %cmp, i32 %sub, i32 0 ret i32 %cond } + +; rdar://10734411 +define i32 @h(i32 %a, i32 %b) nounwind { +entry: +; CHECK: h: +; CHECK-NOT: cmp +; CHECK: cmov + %cmp = icmp slt i32 %b, %a + %sub = sub nsw i32 %a, %b + %cond = select i1 %cmp, i32 %sub, i32 0 + ret i32 %cond +} +define i32 @i(i32 %a, i32 %b) nounwind { +entry: +; CHECK: i: +; CHECK-NOT: cmp +; CHECK: cmov + %cmp = icmp sgt i32 %a, %b + %sub = sub nsw i32 %a, %b + %cond = select i1 %cmp, i32 %sub, i32 0 + ret i32 %cond +} +define i32 @j(i32 %a, i32 %b) nounwind { +entry: +; CHECK: j: +; CHECK-NOT: cmp +; CHECK: cmov + %cmp = icmp ugt i32 %a, %b + %sub = sub i32 %a, %b + %cond = select i1 %cmp, i32 %sub, i32 0 + ret i32 %cond +} +define i32 @k(i32 %a, i32 %b) nounwind { +entry: +; CHECK: k: +; CHECK-NOT: cmp +; CHECK: cmov + %cmp = icmp ult i32 %b, %a + %sub = sub i32 %a, %b + %cond = select i1 %cmp, i32 %sub, i32 0 + ret i32 %cond +}