Skip to content

Commit

Permalink
[SelectionDAG] Use KnownBits::computeForAddSub/computeForAddCarry
Browse files Browse the repository at this point in the history
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
  • Loading branch information
bjope committed Apr 15, 2019
1 parent abd87ff commit 6056936
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 68 deletions.
79 changes: 21 additions & 58 deletions llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
Expand Up @@ -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:
Expand All @@ -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:
Expand Down
19 changes: 9 additions & 10 deletions llvm/test/CodeGen/X86/pr32282.ll
Expand Up @@ -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
Expand Down
42 changes: 42 additions & 0 deletions llvm/unittests/CodeGen/AArch64SelectionDAGTest.cpp
Expand Up @@ -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

0 comments on commit 6056936

Please sign in to comment.