From a2b5600e615feb71840cd66d2676a8938daf737e Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Sun, 5 Dec 2010 01:23:24 +0000 Subject: [PATCH] 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 --- lib/Target/X86/X86ISelLowering.cpp | 54 +++++++++++++++++----------- test/CodeGen/X86/select.ll | 58 ++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 21 deletions(-) diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp index 478bf71c686..3e7b0bbd6ae 100644 --- a/lib/Target/X86/X86ISelLowering.cpp +++ b/lib/Target/X86/X86ISelLowering.cpp @@ -7208,10 +7208,17 @@ static bool isX86LogicalCmp(SDValue Op) { return false; } +static bool isZero(SDValue V) { + ConstantSDNode *C = dyn_cast(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(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(Op1); + + unsigned CondCode =cast(Cond.getOperand(0))->getZExtValue(); + + ConstantSDNode *N1C = dyn_cast(Op1); + ConstantSDNode *N2C = dyn_cast(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(Op2); - ConstantSDNode *RHSC = - dyn_cast(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(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 diff --git a/test/CodeGen/X86/select.ll b/test/CodeGen/X86/select.ll index 9045ccd6be7..9dadbb07410 100644 --- a/test/CodeGen/X86/select.ll +++ b/test/CodeGen/X86/select.ll @@ -86,6 +86,7 @@ define x86_fp80 @test7(i32 %tmp8) nounwind { %tmp9 = icmp sgt i32 %tmp8, -1 ; [#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 +} + + + + + -- 2.34.1