ValueTracking: Figure out more bits when looking at add/sub

Given something like X01XX + X01XX, we know that the result must look
like X1XXX.

Adapted from a patch by Richard Smith, test-case written by me.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@216250 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
David Majnemer 2014-08-22 00:40:43 +00:00
parent 2c0e02e21b
commit 54056f1760
2 changed files with 50 additions and 65 deletions

View File

@ -50,81 +50,53 @@ static void computeKnownBitsAddSub(bool Add, Value *Op0, Value *Op1, bool NSW,
APInt &KnownZero, APInt &KnownOne, APInt &KnownZero, APInt &KnownOne,
APInt &KnownZero2, APInt &KnownOne2, APInt &KnownZero2, APInt &KnownOne2,
const DataLayout *TD, unsigned Depth) { const DataLayout *TD, unsigned Depth) {
if (!Add) {
if (ConstantInt *CLHS = dyn_cast<ConstantInt>(Op0)) {
// 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->getValue().isNegative()) {
unsigned BitWidth = KnownZero.getBitWidth();
unsigned NLZ = (CLHS->getValue()+1).countLeadingZeros();
// NLZ can't be BitWidth with no sign bit
APInt MaskV = APInt::getHighBitsSet(BitWidth, NLZ+1);
llvm::computeKnownBits(Op1, KnownZero2, KnownOne2, TD, 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 ((KnownZero2 & MaskV) == MaskV) {
unsigned NLZ2 = CLHS->getValue().countLeadingZeros();
// Top bits known zero.
KnownZero = APInt::getHighBitsSet(BitWidth, NLZ2);
}
}
}
}
unsigned BitWidth = KnownZero.getBitWidth(); unsigned BitWidth = KnownZero.getBitWidth();
// If one of the operands has trailing zeros, then the bits that the // If an initial sequence of bits in the result is not needed, the
// other operand has in those bit positions will be preserved in the // corresponding bits in the operands are not needed.
// result. For an add, this works with either operand. For a subtract,
// this only works if the known zeros are in the right operand.
APInt LHSKnownZero(BitWidth, 0), LHSKnownOne(BitWidth, 0); APInt LHSKnownZero(BitWidth, 0), LHSKnownOne(BitWidth, 0);
llvm::computeKnownBits(Op0, LHSKnownZero, LHSKnownOne, TD, Depth+1); llvm::computeKnownBits(Op0, LHSKnownZero, LHSKnownOne, TD, Depth+1);
unsigned LHSKnownZeroOut = LHSKnownZero.countTrailingOnes();
llvm::computeKnownBits(Op1, KnownZero2, KnownOne2, TD, Depth+1); llvm::computeKnownBits(Op1, KnownZero2, KnownOne2, TD, Depth+1);
unsigned RHSKnownZeroOut = KnownZero2.countTrailingOnes();
// Determine which operand has more trailing zeros, and use that // Carry in a 1 for a subtract, rather than a 0.
// many bits from the other operand. APInt CarryIn(BitWidth, 0);
if (LHSKnownZeroOut > RHSKnownZeroOut) { if (!Add) {
if (Add) { // Sum = LHS + ~RHS + 1
APInt Mask = APInt::getLowBitsSet(BitWidth, LHSKnownZeroOut); std::swap(KnownZero2, KnownOne2);
KnownZero |= KnownZero2 & Mask; CarryIn.setBit(0);
KnownOne |= KnownOne2 & Mask;
} else {
// If the known zeros are in the left operand for a subtract,
// fall back to the minimum known zeros in both operands.
KnownZero |= APInt::getLowBitsSet(BitWidth,
std::min(LHSKnownZeroOut,
RHSKnownZeroOut));
}
} else if (RHSKnownZeroOut >= LHSKnownZeroOut) {
APInt Mask = APInt::getLowBitsSet(BitWidth, RHSKnownZeroOut);
KnownZero |= LHSKnownZero & Mask;
KnownOne |= LHSKnownOne & Mask;
} }
APInt PossibleSumZero = ~LHSKnownZero + ~KnownZero2 + CarryIn;
APInt PossibleSumOne = LHSKnownOne + KnownOne2 + CarryIn;
// Compute known bits of the carry.
APInt CarryKnownZero = ~(PossibleSumZero ^ LHSKnownZero ^ KnownZero2);
APInt CarryKnownOne = PossibleSumOne ^ LHSKnownOne ^ KnownOne2;
// Compute set of known bits (where all three relevant bits are known).
APInt LHSKnown = LHSKnownZero | LHSKnownOne;
APInt RHSKnown = KnownZero2 | KnownOne2;
APInt CarryKnown = CarryKnownZero | CarryKnownOne;
APInt Known = LHSKnown & RHSKnown & CarryKnown;
assert((PossibleSumZero & Known) == (PossibleSumOne & Known) &&
"known bits of sum differ");
// Compute known bits of the result.
KnownZero = ~PossibleSumOne & Known;
KnownOne = PossibleSumOne & Known;
// Are we still trying to solve for the sign bit? // Are we still trying to solve for the sign bit?
if (!KnownZero.isNegative() && !KnownOne.isNegative()) { if (!Known.isNegative()) {
if (NSW) { if (NSW) {
if (Add) { // Adding two non-negative numbers, or subtracting a negative number from
// Adding two positive numbers can't wrap into negative // a non-negative one, can't wrap into negative.
if (LHSKnownZero.isNegative() && KnownZero2.isNegative()) if (LHSKnownZero.isNegative() && KnownZero2.isNegative())
KnownZero |= APInt::getSignBit(BitWidth); KnownZero |= APInt::getSignBit(BitWidth);
// and adding two negative numbers can't wrap into positive. // Adding two negative numbers, or subtracting a non-negative number from
else if (LHSKnownOne.isNegative() && KnownOne2.isNegative()) // a negative one, can't wrap into non-negative.
KnownOne |= APInt::getSignBit(BitWidth); else if (LHSKnownOne.isNegative() && KnownOne2.isNegative())
} else { KnownOne |= APInt::getSignBit(BitWidth);
// Subtracting a negative number from a positive one can't wrap
if (LHSKnownZero.isNegative() && KnownOne2.isNegative())
KnownZero |= APInt::getSignBit(BitWidth);
// neither can subtracting a positive number from a negative one.
else if (LHSKnownOne.isNegative() && KnownZero2.isNegative())
KnownOne |= APInt::getSignBit(BitWidth);
}
} }
} }
} }

View File

@ -969,3 +969,16 @@ define i1 @icmp_sdiv_neg1(i64 %a) {
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i64 [[DIV]], 1073741824 ; CHECK-NEXT: [[CMP:%.*]] = icmp ne i64 [[DIV]], 1073741824
; CHECK-NEXT: ret i1 [[CMP]] ; CHECK-NEXT: ret i1 [[CMP]]
} }
define i1 @icmp_known_bits(i4 %x, i4 %y) {
%and1 = and i4 %y, -7
%and2 = and i4 %x, -7
%or1 = or i4 %and1, 2
%or2 = or i4 %and2, 2
%add = add i4 %or1, %or2
%cmp = icmp eq i4 %add, 0
ret i1 %cmp
; CHECK-LABEL: @icmp_known_bits
; CHECK-NEXT: ret i1 false
}