mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-11-02 07:11:49 +00:00
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:
parent
63ed439ab5
commit
f43438b6c3
@ -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:
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user