X86: optimization for max-like struct

This patch will optimize the following cases on X86
(a > b) ? (a-b) : 0
(a >= b) ? (a-b) : 0
(b < a) ? (a-b) : 0
(b <= a) ? (a-b) : 0

FROM
movl    %edi, %ecx
subl    %esi, %ecx
cmpl    %edi, %esi
movl    $0, %eax
cmovll  %ecx, %eax
TO
xorl    %eax, %eax
subl    %esi, %edi
cmovll  %eax, %edi
movl    %edi, %eax

rdar: 10734411


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@155919 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp
index 660a1bd..8005e23 100644
--- a/lib/Target/X86/X86ISelLowering.cpp
+++ b/lib/Target/X86/X86ISelLowering.cpp
@@ -8573,6 +8573,46 @@
       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<ConstantSDNode>(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<ConstantSDNode>(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 dbd133c..35f69c9 100644
--- a/test/CodeGen/X86/jump_sign.ll
+++ b/test/CodeGen/X86/jump_sign.ll
@@ -32,3 +32,45 @@
   %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
+}