mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 18:54:02 +01:00
[SelectionDAG] Use KnownBits::computeForAddSub/computeForAddCarry
Summary: Use KnownBits::computeForAddSub/computeForAddCarry in SelectionDAG::computeKnownBits when doing value tracking for addition/subtraction. This should improve the precision of the known bits, as we only used to make a simple estimate of known zeroes. The KnownBits support functions are also able to deduce bits that are known to be one in the result. Reviewers: spatel, RKSimon, nikic, lebedev.ri Reviewed By: nikic Subscribers: nikic, javed.absar, lebedev.ri, hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D60460 llvm-svn: 358372
This commit is contained in:
parent
e9b3885d99
commit
e16d5485e2
@ -2906,39 +2906,10 @@ KnownBits SelectionDAG::computeKnownBits(SDValue Op, const APInt &DemandedElts,
|
||||
LLVM_FALLTHROUGH;
|
||||
case ISD::SUB:
|
||||
case ISD::SUBC: {
|
||||
if (ConstantSDNode *CLHS = isConstOrConstSplat(Op.getOperand(0))) {
|
||||
// We know that the top bits of C-X are clear if X contains less bits
|
||||
// than C (i.e. no wrap-around can happen). For example, 20-X is
|
||||
// positive if we can prove that X is >= 0 and < 16.
|
||||
if (CLHS->getAPIntValue().isNonNegative()) {
|
||||
unsigned NLZ = (CLHS->getAPIntValue()+1).countLeadingZeros();
|
||||
// NLZ can't be BitWidth with no sign bit
|
||||
APInt MaskV = APInt::getHighBitsSet(BitWidth, NLZ+1);
|
||||
Known2 = computeKnownBits(Op.getOperand(1), DemandedElts,
|
||||
Depth + 1);
|
||||
|
||||
// If all of the MaskV bits are known to be zero, then we know the
|
||||
// output top bits are zero, because we now know that the output is
|
||||
// from [0-C].
|
||||
if ((Known2.Zero & MaskV) == MaskV) {
|
||||
unsigned NLZ2 = CLHS->getAPIntValue().countLeadingZeros();
|
||||
// Top bits known zero.
|
||||
Known.Zero.setHighBits(NLZ2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If low bits are know to be zero in both operands, then we know they are
|
||||
// going to be 0 in the result. Both addition and complement operations
|
||||
// preserve the low zero bits.
|
||||
Known2 = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1);
|
||||
unsigned KnownZeroLow = Known2.countMinTrailingZeros();
|
||||
if (KnownZeroLow == 0)
|
||||
break;
|
||||
|
||||
Known = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1);
|
||||
Known2 = computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1);
|
||||
KnownZeroLow = std::min(KnownZeroLow, Known2.countMinTrailingZeros());
|
||||
Known.Zero.setLowBits(KnownZeroLow);
|
||||
Known = KnownBits::computeForAddSub(/* Add */ false, /* NSW */ false,
|
||||
Known, Known2);
|
||||
break;
|
||||
}
|
||||
case ISD::UADDO:
|
||||
@ -2956,34 +2927,26 @@ KnownBits SelectionDAG::computeKnownBits(SDValue Op, const APInt &DemandedElts,
|
||||
case ISD::ADD:
|
||||
case ISD::ADDC:
|
||||
case ISD::ADDE: {
|
||||
// Output known-0 bits are known if clear or set in both the low clear bits
|
||||
// common to both LHS & RHS. For example, 8+(X<<3) is known to have the
|
||||
// low 3 bits clear.
|
||||
// Output known-0 bits are also known if the top bits of each input are
|
||||
// known to be clear. For example, if one input has the top 10 bits clear
|
||||
// and the other has the top 8 bits clear, we know the top 7 bits of the
|
||||
// output must be clear.
|
||||
Known2 = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1);
|
||||
unsigned KnownZeroHigh = Known2.countMinLeadingZeros();
|
||||
unsigned KnownZeroLow = Known2.countMinTrailingZeros();
|
||||
assert(Op.getResNo() == 0 && "We only compute knownbits for the sum here.");
|
||||
|
||||
// With ADDE and ADDCARRY, a carry bit may be added in.
|
||||
KnownBits Carry(1);
|
||||
if (Opcode == ISD::ADDE)
|
||||
// Can't track carry from glue, set carry to unknown.
|
||||
Carry.resetAll();
|
||||
else if (Opcode == ISD::ADDCARRY)
|
||||
// TODO: Compute known bits for the carry operand. Not sure if it is worth
|
||||
// the trouble (how often will we find a known carry bit). And I haven't
|
||||
// tested this very much yet, but something like this might work:
|
||||
// Carry = computeKnownBits(Op.getOperand(2), DemandedElts, Depth + 1);
|
||||
// Carry = Carry.zextOrTrunc(1, false);
|
||||
Carry.resetAll();
|
||||
else
|
||||
Carry.setAllZero();
|
||||
|
||||
Known = computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1);
|
||||
Known2 = computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1);
|
||||
KnownZeroHigh = std::min(KnownZeroHigh, Known2.countMinLeadingZeros());
|
||||
KnownZeroLow = std::min(KnownZeroLow, Known2.countMinTrailingZeros());
|
||||
|
||||
if (Opcode == ISD::ADDE || Opcode == ISD::ADDCARRY) {
|
||||
// With ADDE and ADDCARRY, a carry bit may be added in, so we can only
|
||||
// use this information if we know (at least) that the low two bits are
|
||||
// clear. We then return to the caller that the low bit is unknown but
|
||||
// that other bits are known zero.
|
||||
if (KnownZeroLow >= 2)
|
||||
Known.Zero.setBits(1, KnownZeroLow);
|
||||
break;
|
||||
}
|
||||
|
||||
Known.Zero.setLowBits(KnownZeroLow);
|
||||
if (KnownZeroHigh > 1)
|
||||
Known.Zero.setHighBits(KnownZeroHigh - 1);
|
||||
Known = KnownBits::computeForAddCarry(Known, Known2, Carry);
|
||||
break;
|
||||
}
|
||||
case ISD::SREM:
|
||||
|
@ -13,19 +13,18 @@ define void @foo(i64 %x) nounwind {
|
||||
; X86-LABEL: foo:
|
||||
; X86: # %bb.0:
|
||||
; X86-NEXT: pushl %eax
|
||||
; X86-NEXT: movl d, %eax
|
||||
; X86-NEXT: movl d+4, %eax
|
||||
; X86-NEXT: notl %eax
|
||||
; X86-NEXT: movl d+4, %ecx
|
||||
; X86-NEXT: movl d, %ecx
|
||||
; X86-NEXT: notl %ecx
|
||||
; X86-NEXT: andl $701685459, %ecx # imm = 0x29D2DED3
|
||||
; X86-NEXT: andl $-564453154, %eax # imm = 0xDE5B20DE
|
||||
; X86-NEXT: shrdl $21, %ecx, %eax
|
||||
; X86-NEXT: shrl $21, %ecx
|
||||
; X86-NEXT: andl $-2, %eax
|
||||
; X86-NEXT: addl $7, %eax
|
||||
; X86-NEXT: adcl $0, %ecx
|
||||
; X86-NEXT: pushl %ecx
|
||||
; X86-NEXT: andl $-566231040, %ecx # imm = 0xDE400000
|
||||
; X86-NEXT: andl $701685459, %eax # imm = 0x29D2DED3
|
||||
; X86-NEXT: shrdl $21, %eax, %ecx
|
||||
; X86-NEXT: shrl $21, %eax
|
||||
; X86-NEXT: addl $7, %ecx
|
||||
; X86-NEXT: adcl $0, %eax
|
||||
; X86-NEXT: pushl %eax
|
||||
; X86-NEXT: pushl %ecx
|
||||
; X86-NEXT: pushl {{[0-9]+}}(%esp)
|
||||
; X86-NEXT: pushl {{[0-9]+}}(%esp)
|
||||
; X86-NEXT: calll __divdi3
|
||||
|
@ -157,4 +157,46 @@ TEST_F(AArch64SelectionDAGTest, SimplifyDemandedVectorElts_EXTRACT_SUBVECTOR) {
|
||||
false);
|
||||
}
|
||||
|
||||
// Piggy-backing on the AArch64 tests to verify SelectionDAG::computeKnownBits.
|
||||
TEST_F(AArch64SelectionDAGTest, ComputeKnownBits_ADD) {
|
||||
if (!TM)
|
||||
return;
|
||||
SDLoc Loc;
|
||||
auto IntVT = EVT::getIntegerVT(Context, 8);
|
||||
auto UnknownOp = DAG->getRegister(0, IntVT);
|
||||
auto Mask = DAG->getConstant(0x8A, Loc, IntVT);
|
||||
auto N0 = DAG->getNode(ISD::AND, Loc, IntVT, Mask, UnknownOp);
|
||||
auto N1 = DAG->getConstant(0x55, Loc, IntVT);
|
||||
auto Op = DAG->getNode(ISD::ADD, Loc, IntVT, N0, N1);
|
||||
// N0 = ?000?0?0
|
||||
// N1 = 01010101
|
||||
// =>
|
||||
// Known.One = 01010101 (0x55)
|
||||
// Known.Zero = 00100000 (0x20)
|
||||
KnownBits Known = DAG->computeKnownBits(Op);
|
||||
EXPECT_EQ(Known.Zero, APInt(8, 0x20));
|
||||
EXPECT_EQ(Known.One, APInt(8, 0x55));
|
||||
}
|
||||
|
||||
// Piggy-backing on the AArch64 tests to verify SelectionDAG::computeKnownBits.
|
||||
TEST_F(AArch64SelectionDAGTest, ComputeKnownBits_SUB) {
|
||||
if (!TM)
|
||||
return;
|
||||
SDLoc Loc;
|
||||
auto IntVT = EVT::getIntegerVT(Context, 8);
|
||||
auto N0 = DAG->getConstant(0x55, Loc, IntVT);
|
||||
auto UnknownOp = DAG->getRegister(0, IntVT);
|
||||
auto Mask = DAG->getConstant(0x2e, Loc, IntVT);
|
||||
auto N1 = DAG->getNode(ISD::AND, Loc, IntVT, Mask, UnknownOp);
|
||||
auto Op = DAG->getNode(ISD::SUB, Loc, IntVT, N0, N1);
|
||||
// N0 = 01010101
|
||||
// N1 = 00?0???0
|
||||
// =>
|
||||
// Known.One = 00000001 (0x1)
|
||||
// Known.Zero = 10000000 (0x80)
|
||||
KnownBits Known = DAG->computeKnownBits(Op);
|
||||
EXPECT_EQ(Known.Zero, APInt(8, 0x80));
|
||||
EXPECT_EQ(Known.One, APInt(8, 0x1));
|
||||
}
|
||||
|
||||
} // end anonymous namespace
|
||||
|
Loading…
Reference in New Issue
Block a user