diff --git a/llvm/lib/Support/KnownBits.cpp b/llvm/lib/Support/KnownBits.cpp --- a/llvm/lib/Support/KnownBits.cpp +++ b/llvm/lib/Support/KnownBits.cpp @@ -399,7 +399,14 @@ // Absolute value preserves trailing zero count. KnownBits KnownAbs(getBitWidth()); - KnownAbs.Zero.setLowBits(countMinTrailingZeros()); + + unsigned Max = countMaxTrailingZeros(); + unsigned Min = countMinTrailingZeros(); + + KnownAbs.Zero.setLowBits(Min); + // If we know the lowest set 1, then preserve it. + if (Max == Min && Max < getBitWidth()) + KnownAbs.One.setBit(Max); // We only know that the absolute values's MSB will be zero if INT_MIN is // poison, or there is a set bit that isn't the sign bit (otherwise it could @@ -407,8 +414,19 @@ if (IntMinIsPoison || (!One.isZero() && !One.isMinSignedValue())) KnownAbs.Zero.setSignBit(); - // FIXME: Handle known negative input? - // FIXME: Calculate the negated Known bits and combine them? + // If the input is negative, then abs(x) == -x. + if (isNegative()) { + KnownBits Zero(getBitWidth()); + Zero.setAllZero(); + + KnownBits KnownNeg = computeForAddSub( + /*Add*/ false, /*NSW*/ false, Zero, *this); + + // NB: KnownAbs is not always a subset of KnownNeg so we want to get input + // from both. + KnownAbs.One |= KnownNeg.One; + KnownAbs.Zero |= KnownNeg.Zero; + } return KnownAbs; } diff --git a/llvm/test/Analysis/ValueTracking/knownbits-abs.ll b/llvm/test/Analysis/ValueTracking/knownbits-abs.ll --- a/llvm/test/Analysis/ValueTracking/knownbits-abs.ll +++ b/llvm/test/Analysis/ValueTracking/knownbits-abs.ll @@ -4,12 +4,7 @@ define i1 @abs_low_bit_set(i8 %x) { ; CHECK-LABEL: @abs_low_bit_set( -; CHECK-NEXT: [[XX:%.*]] = and i8 [[X:%.*]], -16 -; CHECK-NEXT: [[V:%.*]] = or i8 [[XX]], 4 -; CHECK-NEXT: [[ABS:%.*]] = call i8 @llvm.abs.i8(i8 [[V]], i1 true) -; CHECK-NEXT: [[AND:%.*]] = and i8 [[ABS]], 4 -; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[AND]], 0 -; CHECK-NEXT: ret i1 [[R]] +; CHECK-NEXT: ret i1 false ; %xx = and i8 %x, 240 %v = or i8 %xx, 4 @@ -36,12 +31,7 @@ define i1 @abs_negative(i8 %x) { ; CHECK-LABEL: @abs_negative( -; CHECK-NEXT: [[XX:%.*]] = and i8 [[X:%.*]], -16 -; CHECK-NEXT: [[V:%.*]] = or i8 [[XX]], -124 -; CHECK-NEXT: [[ABS:%.*]] = call i8 @llvm.abs.i8(i8 [[V]], i1 true) -; CHECK-NEXT: [[AND:%.*]] = and i8 [[ABS]], 8 -; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[AND]], 0 -; CHECK-NEXT: ret i1 [[R]] +; CHECK-NEXT: ret i1 false ; %xx = and i8 %x, 240 %v = or i8 %xx, 132 @@ -53,11 +43,7 @@ define i1 @abs_negative2(i8 %x) { ; CHECK-LABEL: @abs_negative2( -; CHECK-NEXT: [[V:%.*]] = or i8 [[X:%.*]], -125 -; CHECK-NEXT: [[ABS:%.*]] = call i8 @llvm.abs.i8(i8 [[V]], i1 true) -; CHECK-NEXT: [[AND:%.*]] = and i8 [[ABS]], 2 -; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[AND]], 2 -; CHECK-NEXT: ret i1 [[R]] +; CHECK-NEXT: ret i1 false ; %v = or i8 %x, 131 %abs = call i8 @llvm.abs.i8(i8 %v, i1 true)