Skip to content
Merged
16 changes: 16 additions & 0 deletions llvm/lib/Analysis/ValueTracking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,22 @@ static void computeKnownBitsMul(const Value *Op0, const Value *Op1, bool NSW,
Known.makeNonNegative();
else if (isKnownNegative && !Known.isNonNegative())
Known.makeNegative();

// Check if both operands are the same sign-extension of a single value.
const Value *A = nullptr;
if (match(Op0, m_SExt(m_Value(A))) && match(Op1, m_SExt(m_Specific(A)))) {
unsigned SignBits = ComputeNumSignBits(Op0, DemandedElts, Q, Depth + 1);
unsigned TyBits = Op0->getType()->getScalarSizeInBits();
// The output of the Mul can be at most twice the valid bits
unsigned OutValidBits = 2 * (TyBits - SignBits + 1);
unsigned OutSignBits =
OutValidBits > TyBits ? 1 : TyBits - OutValidBits + 1;

if (OutSignBits > 1) {
APInt KnownZeroMask = APInt::getHighBitsSet(TyBits, OutSignBits);
Known.Zero |= KnownZeroMask;
}
}
}

void llvm::computeKnownBitsFromRangeMetadata(const MDNode &Ranges,
Expand Down
33 changes: 33 additions & 0 deletions llvm/test/Analysis/ValueTracking/known-bits.ll
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,36 @@ define i1 @vec_reverse_known_bits_demanded_fail(<4 x i8> %xx) {
%r = icmp slt i8 %ele, 0
ret i1 %r
}

; Test known bits for (sext i8 x) * (sext i8 x)
; RUN: opt -passes=instcombine < %s -S | FileCheck %s --check-prefix=SEXT_SQUARE
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not add an extra run line to this test. If this does not fold through -passes=instsimplify, then this should be tested inside llvm/test/Transforms/InstCombine.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't fold with instsimplify so I moved it into llvm/test/Transforms/InstCombine


define i1 @sext_square_bit31(i8 %x) {
; SEXT_SQUARE-LABEL: @sext_square_bit31(
; SEXT_SQUARE-NEXT: ret i1 false
%sx = sext i8 %x to i32
%mul = mul nsw i32 %sx, %sx
%and = and i32 %mul, 2147483648 ; 1 << 31
%cmp = icmp ne i32 %and, 0
ret i1 %cmp
}

define i1 @sext_square_bit30(i8 %x) {
; SEXT_SQUARE-LABEL: @sext_square_bit30(
; SEXT_SQUARE-NEXT: ret i1 false
%sx = sext i8 %x to i32
%mul = mul nsw i32 %sx, %sx
%and = and i32 %mul, 1073741824 ; 1 << 30
%cmp = icmp ne i32 %and, 0
ret i1 %cmp
}

define i1 @sext_square_bit14(i8 %x) {
; SEXT_SQUARE-LABEL: @sext_square_bit14(
; SEXT_SQUARE-NOT: ret i1 false
%sx = sext i8 %x to i32
%mul = mul nsw i32 %sx, %sx
%and = and i32 %mul, 16384 ; 1 << 14
%cmp = icmp ne i32 %and, 0
ret i1 %cmp
}