X86: Emit test instead of constant shift + compare if the shift result is unused.

This allows us to compile
  return (mask & 0x8 ? a : b);
into
  testb $8, %dil
  cmovnel %edx, %esi
instead of
  andl  $8, %edi
  shrl  $3, %edi
  cmovnel %edx, %esi

which we formed previously because dag combiner canonicalizes setcc of and into shift.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@207088 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Benjamin Kramer 2014-04-24 08:15:31 +00:00
parent 63ed439ab5
commit f43438b6c3
2 changed files with 73 additions and 27 deletions

View File

@ -9668,6 +9668,25 @@ static SDValue LowerVectorAllZeroTest(SDValue Op, const X86Subtarget *Subtarget,
VecIns.back(), VecIns.back());
}
/// \brief return true if \c Op has a use that doesn't just read flags.
static bool hasNonFlagsUse(SDValue Op) {
for (SDNode::use_iterator UI = Op->use_begin(), UE = Op->use_end(); UI != UE;
++UI) {
SDNode *User = *UI;
unsigned UOpNo = UI.getOperandNo();
if (User->getOpcode() == ISD::TRUNCATE && User->hasOneUse()) {
// Look pass truncate.
UOpNo = User->use_begin().getOperandNo();
User = *User->use_begin();
}
if (User->getOpcode() != ISD::BRCOND && User->getOpcode() != ISD::SETCC &&
!(User->getOpcode() == ISD::SELECT && UOpNo == 0))
return true;
}
return false;
}
/// Emit nodes that will be selected as "test Op0,Op0", or something
/// equivalent.
SDValue X86TargetLowering::EmitTest(SDValue Op, unsigned X86CC, SDLoc dl,
@ -9772,31 +9791,34 @@ SDValue X86TargetLowering::EmitTest(SDValue Op, unsigned X86CC, SDLoc dl,
Opcode = X86ISD::ADD;
NumOperands = 2;
break;
case ISD::AND: {
case ISD::SHL:
case ISD::SRL:
// If we have a constant logical shift that's only used in a comparison
// against zero turn it into an equivalent AND. This allows turning it into
// a TEST instruction later.
if (isa<ConstantSDNode>(Op->getOperand(1)) && !hasNonFlagsUse(Op)) {
EVT VT = Op.getValueType();
unsigned BitWidth = VT.getSizeInBits();
unsigned ShAmt = Op->getConstantOperandVal(1);
if (ShAmt >= BitWidth) // Avoid undefined shifts.
break;
APInt Mask = ArithOp.getOpcode() == ISD::SRL
? APInt::getHighBitsSet(BitWidth, BitWidth - ShAmt)
: APInt::getLowBitsSet(BitWidth, BitWidth - ShAmt);
if (!Mask.isSignedIntN(32)) // Avoid large immediates.
break;
SDValue New = DAG.getNode(ISD::AND, dl, VT, Op->getOperand(0),
DAG.getConstant(Mask, VT));
DAG.ReplaceAllUsesWith(Op, New);
Op = New;
}
break;
case ISD::AND:
// If the primary and result isn't used, don't bother using X86ISD::AND,
// because a TEST instruction will be better.
bool NonFlagUse = false;
for (SDNode::use_iterator UI = Op.getNode()->use_begin(),
UE = Op.getNode()->use_end(); UI != UE; ++UI) {
SDNode *User = *UI;
unsigned UOpNo = UI.getOperandNo();
if (User->getOpcode() == ISD::TRUNCATE && User->hasOneUse()) {
// Look pass truncate.
UOpNo = User->use_begin().getOperandNo();
User = *User->use_begin();
}
if (User->getOpcode() != ISD::BRCOND &&
User->getOpcode() != ISD::SETCC &&
!(User->getOpcode() == ISD::SELECT && UOpNo == 0)) {
NonFlagUse = true;
break;
}
}
if (!NonFlagUse)
if (!hasNonFlagsUse(Op))
break;
}
// FALL THROUGH
case ISD::SUB:
case ISD::OR:

View File

@ -26,9 +26,22 @@ cond_true: ; preds = %0
ReturnBlock: ; preds = %0
ret i32 0
; CHECK-LABEL: test2:
; CHECK: movl (%rsi), %eax
; CHECK: shll $3, %eax
; CHECK: testl %eax, %eax
; CHECK: testl $536870911, (%rsi)
}
define i8 @test2b(i8 %X, i8* %y) nounwind {
%tmp = load i8* %y ; <i8> [#uses=1]
%tmp1 = shl i8 %tmp, 3 ; <i8> [#uses=1]
%tmp1.upgrd.2 = icmp eq i8 %tmp1, 0 ; <i1> [#uses=1]
br i1 %tmp1.upgrd.2, label %ReturnBlock, label %cond_true
cond_true: ; preds = %0
ret i8 1
ReturnBlock: ; preds = %0
ret i8 0
; CHECK-LABEL: test2b:
; CHECK: testb $31, (%rsi)
}
define i64 @test3(i64 %x) nounwind {
@ -68,8 +81,8 @@ define i32 @test5(double %A) nounwind {
bb12:; preds = %entry
ret i32 32
; CHECK-LABEL: test5:
; CHECK: ucomisd LCPI4_0(%rip), %xmm0
; CHECK: ucomisd LCPI4_1(%rip), %xmm0
; CHECK: ucomisd LCPI5_0(%rip), %xmm0
; CHECK: ucomisd LCPI5_1(%rip), %xmm0
}
declare i32 @foo(...)
@ -163,3 +176,14 @@ define i32 @test12() uwtable ssp {
}
declare zeroext i1 @test12b()
define i32 @test13(i32 %mask, i32 %base, i32 %intra) {
%and = and i32 %mask, 8
%tobool = icmp ne i32 %and, 0
%cond = select i1 %tobool, i32 %intra, i32 %base
ret i32 %cond
; CHECK-LABEL: test13:
; CHECK: testb $8, %dil
; CHECK: cmovnel
}