diff --git a/lib/Target/X86/README.txt b/lib/Target/X86/README.txt index 181c1bd4a9a..ff32d38005a 100644 --- a/lib/Target/X86/README.txt +++ b/lib/Target/X86/README.txt @@ -1165,58 +1165,6 @@ abs: //===---------------------------------------------------------------------===// -Consider: -int test(unsigned long a, unsigned long b) { return -(a < b); } - -We currently compile this to: - -define i32 @test(i32 %a, i32 %b) nounwind { - %tmp3 = icmp ult i32 %a, %b ; [#uses=1] - %tmp34 = zext i1 %tmp3 to i32 ; [#uses=1] - %tmp5 = sub i32 0, %tmp34 ; [#uses=1] - ret i32 %tmp5 -} - -and - -_test: - movl 8(%esp), %eax - cmpl %eax, 4(%esp) - setb %al - movzbl %al, %eax - negl %eax - ret - -Several deficiencies here. First, we should instcombine zext+neg into sext: - -define i32 @test2(i32 %a, i32 %b) nounwind { - %tmp3 = icmp ult i32 %a, %b ; [#uses=1] - %tmp34 = sext i1 %tmp3 to i32 ; [#uses=1] - ret i32 %tmp34 -} - -However, before we can do that, we have to fix the bad codegen that we get for -sext from bool: - -_test2: - movl 8(%esp), %eax - cmpl %eax, 4(%esp) - setb %al - movzbl %al, %eax - shll $31, %eax - sarl $31, %eax - ret - -This code should be at least as good as the code above. Once this is fixed, we -can optimize this specific case even more to: - - movl 8(%esp), %eax - xorl %ecx, %ecx - cmpl %eax, 4(%esp) - sbbl %ecx, %ecx - -//===---------------------------------------------------------------------===// - Take the following code (from http://gcc.gnu.org/bugzilla/show_bug.cgi?id=16541): diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp index 5290453f05a..fca7b02c40a 100644 --- a/lib/Target/X86/X86ISelLowering.cpp +++ b/lib/Target/X86/X86ISelLowering.cpp @@ -7313,6 +7313,23 @@ SDValue X86TargetLowering::LowerSELECT(SDValue Op, SelectionDAG &DAG) const { Cond = EmitTest(Cond, X86::COND_NE, DAG); } + // a < b ? -1 : 0 -> RES = ~setcc_carry + // a < b ? 0 : -1 -> RES = setcc_carry + // a >= b ? -1 : 0 -> RES = setcc_carry + // a >= b ? 0 : -1 -> RES = ~setcc_carry + if (Cond.getOpcode() == X86ISD::CMP) { + unsigned CondCode = cast(CC)->getZExtValue(); + + if ((CondCode == X86::COND_AE || CondCode == X86::COND_B) && + (isAllOnes(Op1) || isAllOnes(Op2)) && (isZero(Op1) || isZero(Op2))) { + SDValue Res = DAG.getNode(X86ISD::SETCC_CARRY, DL, Op.getValueType(), + DAG.getConstant(X86::COND_B, MVT::i8), Cond); + if (isAllOnes(Op1) != (CondCode == X86::COND_B)) + return DAG.getNOT(DL, Res, Res.getValueType()); + return Res; + } + } + // X86ISD::CMOV means set the result (which is operand 1) to the RHS if // condition is true. SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::Glue); diff --git a/test/CodeGen/X86/select.ll b/test/CodeGen/X86/select.ll index 9df23f17468..ce04e07854a 100644 --- a/test/CodeGen/X86/select.ll +++ b/test/CodeGen/X86/select.ll @@ -197,7 +197,24 @@ entry: declare { i64, i1 } @llvm.umul.with.overflow.i64(i64, i64) nounwind readnone +define i32 @test13(i32 %a, i32 %b) nounwind { + %c = icmp ult i32 %a, %b + %d = sext i1 %c to i32 + ret i32 %d +; CHECK: test13: +; CHECK: cmpl +; CHECK-NEXT: sbbl +; CHECK-NEXT: ret +} - - +define i32 @test14(i32 %a, i32 %b) nounwind { + %c = icmp uge i32 %a, %b + %d = sext i1 %c to i32 + ret i32 %d +; CHECK: test14: +; CHECK: cmpl +; CHECK-NEXT: sbbl +; CHECK-NEXT: notl +; CHECK-NEXT: ret +}