X86: Lower a select directly to a setcc_carry if possible.

int test(unsigned long a, unsigned long b) { return -(a < b); }
compiles to
  _test:                              ## @test
    cmpq  %rsi, %rdi                  ## encoding: [0x48,0x39,0xf7]
    sbbl  %eax, %eax                  ## encoding: [0x19,0xc0]
    ret                               ## encoding: [0xc3]
instead of
  _test:                              ## @test
    xorl  %ecx, %ecx                  ## encoding: [0x31,0xc9]
    cmpq  %rsi, %rdi                  ## encoding: [0x48,0x39,0xf7]
    movl  $-1, %eax                   ## encoding: [0xb8,0xff,0xff,0xff,0xff]
    cmovael %ecx, %eax                ## encoding: [0x0f,0x43,0xc1]
    ret                               ## encoding: [0xc3]


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@122451 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Benjamin Kramer 2010-12-22 23:09:28 +00:00
parent 10b6d33581
commit e915ff30cd
3 changed files with 36 additions and 54 deletions

View File

@ -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 ; <i1> [#uses=1]
%tmp34 = zext i1 %tmp3 to i32 ; <i32> [#uses=1]
%tmp5 = sub i32 0, %tmp34 ; <i32> [#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 ; <i1> [#uses=1]
%tmp34 = sext i1 %tmp3 to i32 ; <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):

View File

@ -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<ConstantSDNode>(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);

View File

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