diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -1109,16 +1109,23 @@ } // and(x, add (x, -1)) is a common idiom that always clears the low bit; + // xor/or(x, add (x, -1)) is an idiom that will always set the low bit. // here we handle the more general case of adding any odd number by - // matching the form and(x, add(x, y)) where y is odd. + // matching the form and/xor/or(x, add(x, y)) where y is odd. // TODO: This could be generalized to clearing any bit set in y where the // following bit is known to be unset in y. - if (IsAnd && !KnownOut.Zero[0] && !KnownOut.One[0] && - match(I, m_c_BinOp(m_Value(X), m_c_Add(m_Deferred(X), m_Value(Y))))) { + if (!KnownOut.Zero[0] && !KnownOut.One[0] && + (match(I, m_c_BinOp(m_Value(X), m_c_Add(m_Deferred(X), m_Value(Y)))) || + match(I, m_c_BinOp(m_Value(X), m_Sub(m_Deferred(X), m_Value(Y)))) || + match(I, m_c_BinOp(m_Value(X), m_Sub(m_Value(Y), m_Deferred(X)))))) { KnownBits KnownY(BitWidth); computeKnownBits(Y, DemandedElts, KnownY, Depth + 1, Q); - if (KnownY.countMinTrailingOnes() > 0) - KnownOut.Zero.setBit(0); + if (KnownY.countMinTrailingOnes() > 0) { + if (IsAnd) + KnownOut.Zero.setBit(0); + else + KnownOut.One.setBit(0); + } } return KnownOut; } diff --git a/llvm/test/Analysis/ValueTracking/knownbits-and-or-xor-lowbit.ll b/llvm/test/Analysis/ValueTracking/knownbits-and-or-xor-lowbit.ll --- a/llvm/test/Analysis/ValueTracking/knownbits-and-or-xor-lowbit.ll +++ b/llvm/test/Analysis/ValueTracking/knownbits-and-or-xor-lowbit.ll @@ -25,10 +25,7 @@ define i32 @cmp_ne_0_sub_xor_eval(i32 %x, i32 %C) { ; CHECK-LABEL: @cmp_ne_0_sub_xor_eval( -; CHECK-NEXT: [[Y:%.*]] = add i32 [[X:%.*]], 1 -; CHECK-NEXT: [[Z:%.*]] = xor i32 [[Y]], [[X]] -; CHECK-NEXT: [[B:%.*]] = and i32 [[Z]], 1 -; CHECK-NEXT: ret i32 [[B]] +; CHECK-NEXT: ret i32 1 ; %C1 = or i32 %C, 13 %y = sub i32 %x, %C1 @@ -50,10 +47,7 @@ define i32 @cmp_ne_0_sub_or_eval(i32 %x, i32 %C) { ; CHECK-LABEL: @cmp_ne_0_sub_or_eval( -; CHECK-NEXT: [[Y:%.*]] = add i32 [[X:%.*]], 1 -; CHECK-NEXT: [[Z:%.*]] = or i32 [[Y]], [[X]] -; CHECK-NEXT: [[B:%.*]] = and i32 [[Z]], 1 -; CHECK-NEXT: ret i32 [[B]] +; CHECK-NEXT: ret i32 1 ; %C1 = or i32 %C, 5 %y = sub i32 %x, %C1