mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-24 19:52:54 +01:00
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 llvm-svn: 120929
This commit is contained in:
parent
c383be807e
commit
474ed0aa9b
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user