Improve an integer select optimization in two ways:

1. generalize 
    (select (x == 0), -1, 0) -> (sign_bit (x - 1))
to:
    (select (x == 0), -1, y) -> (sign_bit (x - 1)) | y

2. Handle the identical pattern that happens with !=:
   (select (x != 0), y, -1) -> (sign_bit (x - 1)) | y

cmov is often high latency and can't fold immediates or
memory operands.  For example for (x == 0) ? -1 : 1, before 
we got:

< 	testb	%sil, %sil
< 	movl	$-1, %ecx
< 	movl	$1, %eax
< 	cmovel	%ecx, %eax

now we get:

> 	cmpb	$1, %sil
> 	sbbl	%eax, %eax
> 	orl	$1, %eax




git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@120929 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Chris Lattner 2010-12-05 01:23:24 +00:00
parent bced6a1b8f
commit a2b5600e61
2 changed files with 91 additions and 21 deletions

View File

@ -7208,10 +7208,17 @@ static bool isX86LogicalCmp(SDValue Op) {
return false;
}
static bool isZero(SDValue V) {
ConstantSDNode *C = dyn_cast<ConstantSDNode>(V);
return C && C->isNullValue();
}
SDValue X86TargetLowering::LowerSELECT(SDValue Op, SelectionDAG &DAG) const {
bool addTest = true;
SDValue Cond = Op.getOperand(0);
DebugLoc dl = Op.getDebugLoc();
SDValue Op1 = Op.getOperand(1);
SDValue Op2 = Op.getOperand(2);
DebugLoc DL = Op.getDebugLoc();
SDValue CC;
if (Cond.getOpcode() == ISD::SETCC) {
@ -7220,30 +7227,35 @@ SDValue X86TargetLowering::LowerSELECT(SDValue Op, SelectionDAG &DAG) const {
Cond = NewCond;
}
// (select (x == 0), -1, 0) -> (sign_bit (x - 1))
SDValue Op1 = Op.getOperand(1);
SDValue Op2 = Op.getOperand(2);
// (select (x == 0), -1, y) -> (sign_bit (x - 1)) | y
// (select (x != 0), y, -1) -> (sign_bit (x - 1)) | y
if (Cond.getOpcode() == X86ISD::SETCC &&
cast<ConstantSDNode>(Cond.getOperand(0))->getZExtValue() == X86::COND_E) {
Cond.getOperand(1).getOpcode() == X86ISD::CMP) {
SDValue Cmp = Cond.getOperand(1);
if (Cmp.getOpcode() == X86ISD::CMP) {
ConstantSDNode *N1C = dyn_cast<ConstantSDNode>(Op1);
unsigned CondCode =cast<ConstantSDNode>(Cond.getOperand(0))->getZExtValue();
ConstantSDNode *N1C = dyn_cast<ConstantSDNode>(Op1);
ConstantSDNode *N2C = dyn_cast<ConstantSDNode>(Op2);
if ((N1C && N1C->isAllOnesValue() && CondCode == X86::COND_E) ||
(N2C && N2C->isAllOnesValue() && CondCode == X86::COND_NE)) {
SDValue Y = CondCode == X86::COND_NE ? Op1 : Op2;
SDValue CmpOp0 = Cmp.getOperand(0);
Cmp = DAG.getNode(X86ISD::CMP, DL, MVT::i32,
CmpOp0, DAG.getConstant(1, CmpOp0.getValueType()));
SDValue Res =
DAG.getNode(X86ISD::SETCC_CARRY, DL, Op.getValueType(),
DAG.getConstant(X86::COND_B, MVT::i8), Cmp);
ConstantSDNode *N2C = dyn_cast<ConstantSDNode>(Op2);
ConstantSDNode *RHSC =
dyn_cast<ConstantSDNode>(Cmp.getOperand(1).getNode());
if (N1C && N1C->isAllOnesValue() &&
N2C && N2C->isNullValue() &&
RHSC && RHSC->isNullValue()) {
SDValue CmpOp0 = Cmp.getOperand(0);
Cmp = DAG.getNode(X86ISD::CMP, dl, MVT::i32,
CmpOp0, DAG.getConstant(1, CmpOp0.getValueType()));
return DAG.getNode(X86ISD::SETCC_CARRY, dl, Op.getValueType(),
DAG.getConstant(X86::COND_B, MVT::i8), Cmp);
}
if (N2C == 0 || !N2C->isNullValue())
Res = DAG.getNode(ISD::OR, DL, Res.getValueType(), Res, Y);
return Res;
}
}
// Look pass (and (setcc_carry (cmp ...)), 1).
// Look past (and (setcc_carry (cmp ...)), 1).
if (Cond.getOpcode() == ISD::AND &&
Cond.getOperand(0).getOpcode() == X86ISD::SETCC_CARRY) {
ConstantSDNode *C = dyn_cast<ConstantSDNode>(Cond.getOperand(1));
@ -7281,7 +7293,7 @@ SDValue X86TargetLowering::LowerSELECT(SDValue Op, SelectionDAG &DAG) const {
// We know the result of AND is compared against zero. Try to match
// it to BT.
if (Cond.getOpcode() == ISD::AND && Cond.hasOneUse()) {
SDValue NewSetCC = LowerToBT(Cond, ISD::SETNE, dl, DAG);
SDValue NewSetCC = LowerToBT(Cond, ISD::SETNE, DL, DAG);
if (NewSetCC.getNode()) {
CC = NewSetCC.getOperand(0);
Cond = NewSetCC.getOperand(1);
@ -7299,7 +7311,7 @@ SDValue X86TargetLowering::LowerSELECT(SDValue Op, SelectionDAG &DAG) const {
// condition is true.
SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::Flag);
SDValue Ops[] = { Op2, Op1, CC, Cond };
return DAG.getNode(X86ISD::CMOV, dl, VTs, Ops, array_lengthof(Ops));
return DAG.getNode(X86ISD::CMOV, DL, VTs, Ops, array_lengthof(Ops));
}
// isAndOrOfSingleUseSetCCs - Return true if node is an ISD::AND or

View File

@ -86,6 +86,7 @@ define x86_fp80 @test7(i32 %tmp8) nounwind {
%tmp9 = icmp sgt i32 %tmp8, -1 ; <i1> [#uses=1]
%retval = select i1 %tmp9, x86_fp80 0xK4005B400000000000000, x86_fp80 0xK40078700000000000000
ret x86_fp80 %retval
; CHECK: test7:
; CHECK: leaq
; CHECK: fldt (%r{{.}}x,%r{{.}}x)
}
@ -96,4 +97,61 @@ define void @test8(i1 %c, <6 x i32>* %dst.addr, <6 x i32> %src1,<6 x i32> %src2)
%val = sub <6 x i32> %x, < i32 1, i32 1, i32 1, i32 1, i32 1, i32 1 >
store <6 x i32> %val, <6 x i32>* %dst.addr
ret void
; CHECK: test8:
}
;; Test integer select between values and constants.
define i64 @test9(i64 %x, i64 %y) nounwind readnone ssp noredzone {
%cmp = icmp ne i64 %x, 0
%cond = select i1 %cmp, i64 %y, i64 -1
ret i64 %cond
; CHECK: test9:
; CHECK: cmpq $1, %rdi
; CHECK: sbbq %rax, %rax
; CHECK: orq %rsi, %rax
; CHECK: ret
}
;; Same as test9
define i64 @test9a(i64 %x, i64 %y) nounwind readnone ssp noredzone {
%cmp = icmp eq i64 %x, 0
%cond = select i1 %cmp, i64 -1, i64 %y
ret i64 %cond
; CHECK: test9a:
; CHECK: cmpq $1, %rdi
; CHECK: sbbq %rax, %rax
; CHECK: orq %rsi, %rax
; CHECK: ret
}
define i64 @test9b(i64 %x, i64 %y) nounwind readnone ssp noredzone {
%cmp = icmp eq i64 %x, 0
%A = sext i1 %cmp to i64
%cond = or i64 %y, %A
ret i64 %cond
; CHECK: test9b:
; CHECK: cmpq $1, %rdi
; CHECK: sbbq %rax, %rax
; CHECK: orq %rsi, %rax
; CHECK: ret
}
;; Select between -1 and 1.
define i64 @test10(i64 %x, i64 %y) nounwind readnone ssp noredzone {
%cmp = icmp eq i64 %x, 0
%cond = select i1 %cmp, i64 -1, i64 1
ret i64 %cond
; CHECK: test10:
; CHECK: cmpq $1, %rdi
; CHECK: sbbq %rax, %rax
; CHECK: orq $1, %rax
; CHECK: ret
}