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
+}