From 4450e73b5e8e214d848875eb8286f5b6448e1605 Mon Sep 17 00:00:00 2001 From: Sanjay Patel Date: Wed, 12 Jul 2017 17:56:46 +0000 Subject: [PATCH] [x86] improve SBB optimizations for SETB/SETA with subtract This is another step towards removing a combine that turns sext into select of constants and preparing the backend for an IR future where select is the canonical form. Earlier commits in this area: https://reviews.llvm.org/rL306040 https://reviews.llvm.org/rL306072 https://reviews.llvm.org/rL307404 (https://reviews.llvm.org/D34652) https://reviews.llvm.org/rL307471 llvm-svn: 307821 --- llvm/lib/Target/X86/X86ISelLowering.cpp | 59 ++++++++++++++++++--------------- llvm/test/CodeGen/X86/sbb.ll | 7 ++-- 2 files changed, 35 insertions(+), 31 deletions(-) diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp index 3d08037..ad3f412 100644 --- a/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -35005,43 +35005,50 @@ static SDValue combineAddOrSubToADCOrSBB(SDNode *N, SelectionDAG &DAG) { EVT VT = N->getValueType(0); X86::CondCode CC = (X86::CondCode)Y.getConstantOperandVal(0); - if (CC == X86::COND_B) { - // X + SETB Z --> X + (mask SBB Z, Z) - // X - SETB Z --> X - (mask SBB Z, Z) - // TODO: Produce ADC/SBB here directly and avoid SETCC_CARRY? - SDValue SBB = materializeSBB(Y.getNode(), Y.getOperand(1), DAG); - if (SBB.getValueSizeInBits() != VT.getSizeInBits()) - SBB = DAG.getZExtOrTrunc(SBB, DL, VT); - return DAG.getNode(IsSub ? ISD::SUB : ISD::ADD, DL, VT, X, SBB); - } - + // If X is -1 or 0, then we have an opportunity to avoid constants required in + // the general case below. auto *ConstantX = dyn_cast(X); - if (!IsSub && ConstantX && ConstantX->isAllOnesValue()) { - if (CC == X86::COND_AE) { + if (ConstantX) { + if ((!IsSub && CC == X86::COND_AE && ConstantX->isAllOnesValue()) || + (IsSub && CC == X86::COND_B && ConstantX->isNullValue())) { // This is a complicated way to get -1 or 0 from the carry flag: // -1 + SETAE --> -1 + (!CF) --> CF ? -1 : 0 --> SBB %eax, %eax - // We don't have to match the subtract equivalent because sub X, 1 is - // canonicalized to add X, -1. + // 0 - SETB --> 0 - (CF) --> CF ? -1 : 0 --> SBB %eax, %eax return DAG.getNode(X86ISD::SETCC_CARRY, DL, VT, DAG.getConstant(X86::COND_B, DL, MVT::i8), Y.getOperand(1)); } - SDValue EFLAGS = Y->getOperand(1); - if (CC == X86::COND_BE && EFLAGS.getOpcode() == X86ISD::SUB && - EFLAGS.hasOneUse() && EFLAGS.getValueType().isInteger() && - !isa(EFLAGS.getOperand(1))) { - // Swap the operands of a SUB, and we have the same pattern as above. - // -1 + SETBE (SUB A, B) --> -1 + SETAE (SUB B, A) --> SBB %eax, %eax - SDValue NewSub = - DAG.getNode(X86ISD::SUB, SDLoc(EFLAGS), EFLAGS.getNode()->getVTList(), - EFLAGS.getOperand(1), EFLAGS.getOperand(0)); - SDValue NewEFLAGS = SDValue(NewSub.getNode(), EFLAGS.getResNo()); - return DAG.getNode(X86ISD::SETCC_CARRY, DL, VT, - DAG.getConstant(X86::COND_B, DL, MVT::i8), NewEFLAGS); + if ((!IsSub && CC == X86::COND_BE && ConstantX->isAllOnesValue()) || + (IsSub && CC == X86::COND_A && ConstantX->isNullValue())) { + SDValue EFLAGS = Y->getOperand(1); + if (EFLAGS.getOpcode() == X86ISD::SUB && EFLAGS.hasOneUse() && + EFLAGS.getValueType().isInteger() && + !isa(EFLAGS.getOperand(1))) { + // Swap the operands of a SUB, and we have the same pattern as above. + // -1 + SETBE (SUB A, B) --> -1 + SETAE (SUB B, A) --> SUB + SBB + // 0 - SETA (SUB A, B) --> 0 - SETB (SUB B, A) --> SUB + SBB + SDValue NewSub = DAG.getNode( + X86ISD::SUB, SDLoc(EFLAGS), EFLAGS.getNode()->getVTList(), + EFLAGS.getOperand(1), EFLAGS.getOperand(0)); + SDValue NewEFLAGS = SDValue(NewSub.getNode(), EFLAGS.getResNo()); + return DAG.getNode(X86ISD::SETCC_CARRY, DL, VT, + DAG.getConstant(X86::COND_B, DL, MVT::i8), + NewEFLAGS); + } } } + if (CC == X86::COND_B) { + // X + SETB Z --> X + (mask SBB Z, Z) + // X - SETB Z --> X - (mask SBB Z, Z) + // TODO: Produce ADC/SBB here directly and avoid SETCC_CARRY? + SDValue SBB = materializeSBB(Y.getNode(), Y.getOperand(1), DAG); + if (SBB.getValueSizeInBits() != VT.getSizeInBits()) + SBB = DAG.getZExtOrTrunc(SBB, DL, VT); + return DAG.getNode(IsSub ? ISD::SUB : ISD::ADD, DL, VT, X, SBB); + } + if (CC == X86::COND_A) { SDValue EFLAGS = Y->getOperand(1); // Try to convert COND_A into COND_B in an attempt to facilitate diff --git a/llvm/test/CodeGen/X86/sbb.ll b/llvm/test/CodeGen/X86/sbb.ll index e5025dc..b6e8ebf 100644 --- a/llvm/test/CodeGen/X86/sbb.ll +++ b/llvm/test/CodeGen/X86/sbb.ll @@ -191,9 +191,8 @@ define i32 @uge_select_0_or_neg1_sub(i32 %x, i32 %y) nounwind { define i64 @ugt_select_neg1_or_0_sub(i64 %x, i64 %y) nounwind { ; CHECK-LABEL: ugt_select_neg1_or_0_sub: ; CHECK: # BB#0: -; CHECK-NEXT: xorl %eax, %eax ; CHECK-NEXT: cmpq %rdi, %rsi -; CHECK-NEXT: sbbq $0, %rax +; CHECK-NEXT: sbbq %rax, %rax ; CHECK-NEXT: retq %cmp = icmp ugt i64 %x, %y %zext = zext i1 %cmp to i64 @@ -207,10 +206,8 @@ define i64 @ugt_select_neg1_or_0_sub(i64 %x, i64 %y) nounwind { define i16 @ult_select_neg1_or_0_sub(i16 %x, i16 %y) nounwind { ; CHECK-LABEL: ult_select_neg1_or_0_sub: ; CHECK: # BB#0: -; CHECK-NEXT: xorl %eax, %eax ; CHECK-NEXT: cmpw %di, %si -; CHECK-NEXT: sbbl $0, %eax -; CHECK-NEXT: # kill: %AX %AX %EAX +; CHECK-NEXT: sbbw %ax, %ax ; CHECK-NEXT: retq %cmp = icmp ult i16 %y, %x %zext = zext i1 %cmp to i16 -- 2.7.4