Some dag combiner goodness:

Transform br (xor (x, y)) -> br (x != y)
Transform br (xor (xor (x,y), 1)) -> br (x == y)
Also normalize (and (X, 1) == / != 1 -> (and (X, 1)) != / == 0 to match to "test on x86" and "tst on arm"


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@96556 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Evan Cheng 2010-02-18 02:13:50 +00:00
parent ca82a15ad1
commit 89bb7b5640
7 changed files with 117 additions and 89 deletions

View File

@ -4655,7 +4655,8 @@ SDValue DAGCombiner::visitBRCOND(SDNode *N) {
DAG.DeleteNode(Trunc);
}
// Replace the uses of SRL with SETCC
DAG.ReplaceAllUsesOfValueWith(N1, SetCC);
WorkListRemover DeadNodes(*this);
DAG.ReplaceAllUsesOfValueWith(N1, SetCC, &DeadNodes);
removeFromWorkList(N1.getNode());
DAG.DeleteNode(N1.getNode());
return SDValue(N, 0); // Return N so it doesn't get rechecked!
@ -4663,6 +4664,53 @@ SDValue DAGCombiner::visitBRCOND(SDNode *N) {
}
}
}
// Transform br(xor(x, y)) -> br(x != y)
// Transform br(xor(xor(x,y), 1)) -> br (x == y)
if (N1.hasOneUse() && N1.getOpcode() == ISD::XOR) {
SDNode *TheXor = N1.getNode();
SDValue Op0 = TheXor->getOperand(0);
SDValue Op1 = TheXor->getOperand(1);
if (Op0.getOpcode() == Op1.getOpcode()) {
// Avoid missing important xor optimizations.
SDValue Tmp = visitXOR(TheXor);
if (Tmp.getNode()) {
DEBUG(dbgs() << "\nReplacing.8 ";
TheXor->dump(&DAG);
dbgs() << "\nWith: ";
Tmp.getNode()->dump(&DAG);
dbgs() << '\n');
WorkListRemover DeadNodes(*this);
DAG.ReplaceAllUsesOfValueWith(N1, Tmp, &DeadNodes);
removeFromWorkList(TheXor);
DAG.DeleteNode(TheXor);
return DAG.getNode(ISD::BRCOND, N->getDebugLoc(),
MVT::Other, Chain, Tmp, N2);
}
}
if (Op0.getOpcode() != ISD::SETCC && Op1.getOpcode() != ISD::SETCC) {
bool Equal = false;
if (ConstantSDNode *RHSCI = dyn_cast<ConstantSDNode>(Op0))
if (RHSCI->getAPIntValue() == 1 && Op0.hasOneUse() &&
Op0.getOpcode() == ISD::XOR) {
TheXor = Op0.getNode();
Equal = true;
}
SDValue SetCC = DAG.getSetCC(TheXor->getDebugLoc(),
TLI.getSetCCResultType(N1.getValueType()),
Op0, Op1,
Equal ? ISD::SETEQ : ISD::SETNE);
// Replace the uses of XOR with SETCC
WorkListRemover DeadNodes(*this);
DAG.ReplaceAllUsesOfValueWith(N1, SetCC, &DeadNodes);
removeFromWorkList(N1.getNode());
DAG.DeleteNode(N1.getNode());
return DAG.getNode(ISD::BRCOND, N->getDebugLoc(),
MVT::Other, Chain, SetCC, N2);
}
}
return SDValue();
}
@ -5012,7 +5060,7 @@ SDValue DAGCombiner::visitLOAD(SDNode *N) {
assert(N->getValueType(2) == MVT::Other && "Malformed indexed loads?");
if (N->hasNUsesOfValue(0, 0) && N->hasNUsesOfValue(0, 1)) {
SDValue Undef = DAG.getUNDEF(N->getValueType(0));
DEBUG(dbgs() << "\nReplacing.6 ";
DEBUG(dbgs() << "\nReplacing.7 ";
N->dump(&DAG);
dbgs() << "\nWith: ";
Undef.getNode()->dump(&DAG);

View File

@ -1775,7 +1775,7 @@ TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1,
break; // todo, be more careful with signed comparisons
}
} else if (N0.getOpcode() == ISD::SIGN_EXTEND_INREG &&
(Cond == ISD::SETEQ || Cond == ISD::SETNE)) {
(Cond == ISD::SETEQ || Cond == ISD::SETNE)) {
EVT ExtSrcTy = cast<VTSDNode>(N0.getOperand(1))->getVT();
unsigned ExtSrcTyBits = ExtSrcTy.getSizeInBits();
EVT ExtDstTy = N0.getValueType();
@ -1809,7 +1809,6 @@ TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1,
Cond);
} else if ((N1C->isNullValue() || N1C->getAPIntValue() == 1) &&
(Cond == ISD::SETEQ || Cond == ISD::SETNE)) {
// SETCC (SETCC), [0|1], [EQ|NE] -> SETCC
if (N0.getOpcode() == ISD::SETCC) {
bool TrueWhenTrue = (Cond == ISD::SETEQ) ^ (N1C->getAPIntValue() != 1);
@ -1822,9 +1821,9 @@ TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1,
N0.getOperand(0).getValueType().isInteger());
return DAG.getSetCC(dl, VT, N0.getOperand(0), N0.getOperand(1), CC);
}
if ((N0.getOpcode() == ISD::XOR ||
(N0.getOpcode() == ISD::AND &&
(N0.getOpcode() == ISD::AND &&
N0.getOperand(0).getOpcode() == ISD::XOR &&
N0.getOperand(1) == N0.getOperand(0).getOperand(1))) &&
isa<ConstantSDNode>(N0.getOperand(1)) &&
@ -1847,9 +1846,26 @@ TargetLowering::SimplifySetCC(EVT VT, SDValue N0, SDValue N1,
N0.getOperand(0).getOperand(0),
N0.getOperand(1));
}
return DAG.getSetCC(dl, VT, Val, N1,
Cond == ISD::SETEQ ? ISD::SETNE : ISD::SETEQ);
}
} else if (N1C->getAPIntValue() == 1) {
// If this is (X&1) == / != 1, normalize it to (X&1) != / == 0.
SDValue Op0 = N0;
if (Op0.getOpcode() == ISD::TRUNCATE)
Op0 = Op0.getOperand(0);
if (Op0.getOpcode() == ISD::AND &&
isa<ConstantSDNode>(Op0.getOperand(1)) &&
cast<ConstantSDNode>(Op0.getOperand(1))->getAPIntValue() == 1) {
if (Op0.getValueType() != VT)
Op0 = DAG.getNode(ISD::AND, dl, VT,
DAG.getNode(ISD::TRUNCATE, dl, VT, Op0.getOperand(0)),
DAG.getConstant(1, VT));
return DAG.getSetCC(dl, VT, Op0,
DAG.getConstant(0, Op0.getValueType()),
Cond == ISD::SETEQ ? ISD::SETNE : ISD::SETEQ);
}
}
}

View File

@ -5874,26 +5874,31 @@ SDValue X86TargetLowering::EmitCmp(SDValue Op0, SDValue Op1, unsigned X86CC,
/// LowerToBT - Result of 'and' is compared against zero. Turn it into a BT node
/// if it's possible.
static SDValue LowerToBT(SDValue Op0, ISD::CondCode CC,
static SDValue LowerToBT(SDValue And, ISD::CondCode CC,
DebugLoc dl, SelectionDAG &DAG) {
SDValue Op0 = And.getOperand(0);
SDValue Op1 = And.getOperand(1);
if (Op0.getOpcode() == ISD::TRUNCATE)
Op0 = Op0.getOperand(0);
if (Op1.getOpcode() == ISD::TRUNCATE)
Op1 = Op1.getOperand(0);
SDValue LHS, RHS;
if (Op0.getOperand(1).getOpcode() == ISD::SHL) {
if (ConstantSDNode *Op010C =
dyn_cast<ConstantSDNode>(Op0.getOperand(1).getOperand(0)))
if (Op010C->getZExtValue() == 1) {
LHS = Op0.getOperand(0);
RHS = Op0.getOperand(1).getOperand(1);
if (Op1.getOpcode() == ISD::SHL) {
if (ConstantSDNode *And10C = dyn_cast<ConstantSDNode>(Op1.getOperand(0)))
if (And10C->getZExtValue() == 1) {
LHS = Op0;
RHS = Op1.getOperand(1);
}
} else if (Op0.getOperand(0).getOpcode() == ISD::SHL) {
if (ConstantSDNode *Op000C =
dyn_cast<ConstantSDNode>(Op0.getOperand(0).getOperand(0)))
if (Op000C->getZExtValue() == 1) {
LHS = Op0.getOperand(1);
RHS = Op0.getOperand(0).getOperand(1);
} else if (Op0.getOpcode() == ISD::SHL) {
if (ConstantSDNode *And00C = dyn_cast<ConstantSDNode>(Op0.getOperand(0)))
if (And00C->getZExtValue() == 1) {
LHS = Op1;
RHS = Op0.getOperand(1);
}
} else if (Op0.getOperand(1).getOpcode() == ISD::Constant) {
ConstantSDNode *AndRHS = cast<ConstantSDNode>(Op0.getOperand(1));
SDValue AndLHS = Op0.getOperand(0);
} else if (Op1.getOpcode() == ISD::Constant) {
ConstantSDNode *AndRHS = cast<ConstantSDNode>(Op1);
SDValue AndLHS = Op0;
if (AndRHS->getZExtValue() == 1 && AndLHS.getOpcode() == ISD::SRL) {
LHS = AndLHS.getOperand(0);
RHS = AndLHS.getOperand(1);
@ -5943,6 +5948,17 @@ SDValue X86TargetLowering::LowerSETCC(SDValue Op, SelectionDAG &DAG) {
return NewSetCC;
}
// Look for "(setcc) == / != 1" to avoid unncessary setcc.
if (Op0.getOpcode() == X86ISD::SETCC &&
Op1.getOpcode() == ISD::Constant &&
cast<ConstantSDNode>(Op1)->getZExtValue() == 1 &&
(CC == ISD::SETEQ || CC == ISD::SETNE)) {
X86::CondCode CCode = (X86::CondCode)Op0.getConstantOperandVal(0);
CCode = X86::GetOppositeBranchCondition(CCode);
return DAG.getNode(X86ISD::SETCC, dl, MVT::i8,
DAG.getConstant(CCode, MVT::i8), Op0.getOperand(1));
}
bool isFP = Op.getOperand(1).getValueType().isFloatingPoint();
unsigned X86CC = TranslateX86CC(CC, isFP, Op0, Op1, DAG);
if (X86CC == X86::COND_INVALID)

View File

@ -1,4 +1,4 @@
; RUN: llc < %s -mtriple=i386-apple-darwin -tailcallopt=false -stats -info-output-file - | grep asm-printer | grep 31
; RUN: llc < %s -mtriple=i386-apple-darwin -stats -info-output-file - | grep asm-printer | grep 29
%CC = type { %Register }
%II = type { %"struct.XX::II::$_74" }

View File

@ -1,4 +1,4 @@
; RUN: llc < %s -march=x86-64 | grep mov | count 5
; RUN: llc < %s -march=x86-64 | grep mov | count 3
%struct.COMPOSITE = type { i8, i16, i16 }
%struct.FILE = type { i8*, i32, i32, i16, i16, %struct.__sbuf, i32, i8*, i32 (i8*)*, i32 (i8*, i8*, i32)*, i64 (i8*, i64, i32)*, i32 (i8*, i8*, i32)*, %struct.__sbuf, %struct.__sFILEX*, i32, [3 x i8], [1 x i8], %struct.__sbuf, i32, i64 }

View File

@ -1,57 +0,0 @@
; RUN: llc < %s -asm-verbose=false -mtriple=x86_64-linux-gnu | FileCheck %s
; PR4126
; PR4732
; Don't omit these labels' definitions.
; CHECK: bux:
; CHECK: LBB1_1:
define void @bux(i32 %p_53) nounwind optsize {
entry:
%0 = icmp eq i32 %p_53, 0 ; <i1> [#uses=1]
%1 = icmp sgt i32 %p_53, 0 ; <i1> [#uses=1]
%or.cond = and i1 %0, %1 ; <i1> [#uses=1]
br i1 %or.cond, label %bb.i, label %bb3
bb.i: ; preds = %entry
%2 = add i32 %p_53, 1 ; <i32> [#uses=1]
%3 = icmp slt i32 %2, 0 ; <i1> [#uses=0]
br label %bb3
bb3: ; preds = %bb.i, %entry
%4 = tail call i32 (...)* @baz(i32 0) nounwind ; <i32> [#uses=0]
ret void
}
declare i32 @baz(...)
; Don't omit this label in the assembly output.
; CHECK: int321:
; CHECK: LBB2_1
; CHECK: LBB2_1
; CHECK: LBB2_1:
define void @int321(i8 signext %p_103, i32 %uint8p_104) nounwind readnone {
entry:
%tobool = icmp eq i8 %p_103, 0 ; <i1> [#uses=1]
%cmp.i = icmp sgt i8 %p_103, 0 ; <i1> [#uses=1]
%or.cond = and i1 %tobool, %cmp.i ; <i1> [#uses=1]
br i1 %or.cond, label %land.end.i, label %for.cond.preheader
land.end.i: ; preds = %entry
%conv3.i = sext i8 %p_103 to i32 ; <i32> [#uses=1]
%div.i = sdiv i32 1, %conv3.i ; <i32> [#uses=1]
%tobool.i = icmp eq i32 %div.i, -2147483647 ; <i1> [#uses=0]
br label %for.cond.preheader
for.cond.preheader: ; preds = %land.end.i, %entry
%cmp = icmp sgt i8 %p_103, 1 ; <i1> [#uses=1]
br i1 %cmp, label %for.end.split, label %for.cond
for.cond: ; preds = %for.cond.preheader, %for.cond
br label %for.cond
for.end.split: ; preds = %for.cond.preheader
ret void
}

View File

@ -3,13 +3,14 @@
; value and as the operand of a branch.
; RUN: llc < %s -march=x86 | FileCheck %s
define i1 @test1(i32 %X) zeroext {
define i1 @test1(i32 %X) zeroext nounwind {
%Y = trunc i32 %X to i1
ret i1 %Y
}
; CHECK: test1:
; CHECK: andl $1, %eax
define i1 @test2(i32 %val, i32 %mask) {
define i1 @test2(i32 %val, i32 %mask) nounwind {
entry:
%shifted = ashr i32 %val, %mask
%anded = and i32 %shifted, 1
@ -20,9 +21,10 @@ ret_true:
ret_false:
ret i1 false
}
; CHECK: testb $1, %al
; CHECK: test2:
; CHECK: btl %eax
define i32 @test3(i8* %ptr) {
define i32 @test3(i8* %ptr) nounwind {
%val = load i8* %ptr
%tmp = trunc i8 %val to i1
br i1 %tmp, label %cond_true, label %cond_false
@ -31,9 +33,10 @@ cond_true:
cond_false:
ret i32 42
}
; CHECK: testb $1, %al
; CHECK: test3:
; CHECK: testb $1, (%eax)
define i32 @test4(i8* %ptr) {
define i32 @test4(i8* %ptr) nounwind {
%tmp = ptrtoint i8* %ptr to i1
br i1 %tmp, label %cond_true, label %cond_false
cond_true:
@ -41,9 +44,10 @@ cond_true:
cond_false:
ret i32 42
}
; CHECK: testb $1, %al
; CHECK: test4:
; CHECK: testb $1, 4(%esp)
define i32 @test6(double %d) {
define i32 @test5(double %d) nounwind {
%tmp = fptosi double %d to i1
br i1 %tmp, label %cond_true, label %cond_false
cond_true:
@ -51,4 +55,5 @@ cond_true:
cond_false:
ret i32 42
}
; CHECK: test5:
; CHECK: testb $1