mirror of
https://github.com/RPCSX/llvm.git
synced 2025-02-01 10:02:42 +00:00
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:
parent
2c0e02e21b
commit
54056f1760
@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user