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,16 +399,41 @@ // Absolute value preserves trailing zero count. KnownBits KnownAbs(getBitWidth()); - KnownAbs.Zero.setLowBits(countMinTrailingZeros()); + + unsigned MaxTZ = countMaxTrailingZeros(); + unsigned MinTZ = countMinTrailingZeros(); + + KnownAbs.Zero.setLowBits(MinTZ); + // If we know the lowest set 1, then preserve it. + if (MaxTZ == MinTZ && MaxTZ < getBitWidth()) + KnownAbs.One.setBit(MaxTZ); // 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 // be INT_MIN). - if (IntMinIsPoison || (!One.isZero() && !One.isMinSignedValue())) + if (IntMinIsPoison || (!One.isZero() && !One.isMinSignedValue())) { + KnownAbs.One.clearSignBit(); KnownAbs.Zero.setSignBit(); + } + + // 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); + + // Preserve signbit from `KnownAbs` as it has additional logic for figuring + // it out that we don't want to duplicate here. + KnownNeg.One.clearSignBit(); + KnownNeg.Zero.clearSignBit(); + + KnownAbs.One |= KnownNeg.One; + KnownAbs.Zero |= KnownNeg.Zero; + } - // FIXME: Handle known negative input? - // FIXME: Calculate the negated Known bits and combine them? + assert(!KnownAbs.hasConflict() && "Bad Output"); 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)