From: Noah Goldstein Date: Thu, 26 Jan 2023 17:35:51 +0000 (-0600) Subject: Add logic for tracking lowbit of (and/xor/or X, (add/sub X, Odd)) X-Git-Tag: upstream/17.0.6~16605 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=196d3e39653c66b6809680e2ae725f7a688f672f;p=platform%2Fupstream%2Fllvm.git Add logic for tracking lowbit of (and/xor/or X, (add/sub X, Odd)) Any case of logicop + add/sub(Odd) we can prove the low bit is either zero/non-zero. Alive2 Links: xor: sub x, C: https://alive2.llvm.org/ce/z/aaABdS sub C, x: https://alive2.llvm.org/ce/z/2W-ZJ7 add C, x: https://alive2.llvm.org/ce/z/pzDkte or: sub x, C: https://alive2.llvm.org/ce/z/xd-bcP sub C, x: https://alive2.llvm.org/ce/z/p8hXJF add C, x: https://alive2.llvm.org/ce/z/osmkB6 and: sub x, C: https://alive2.llvm.org/ce/z/D_NNxR sub C, x: https://alive2.llvm.org/ce/z/N_5C62 add C, x: https://alive2.llvm.org/ce/z/4cy7a4 Differential Revision: https://reviews.llvm.org/D142427 --- diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index 098af26..94ec351 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -1115,16 +1115,23 @@ static KnownBits getKnownBitsFromAndXorOr(const Operator *I, } // 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 index 6573ffe..3b5602b 100644 --- a/llvm/test/Analysis/ValueTracking/knownbits-and-or-xor-lowbit.ll +++ b/llvm/test/Analysis/ValueTracking/knownbits-and-or-xor-lowbit.ll @@ -3,11 +3,7 @@ define <2 x i1> @sub_XY_and_bit0_is_zero(<2 x i8> %x, <2 x i8> %C) nounwind { ; CHECK-LABEL: @sub_XY_and_bit0_is_zero( -; CHECK-NEXT: [[C1:%.*]] = or <2 x i8> [[C:%.*]], -; CHECK-NEXT: [[Y:%.*]] = sub <2 x i8> [[X:%.*]], [[C1]] -; CHECK-NEXT: [[W:%.*]] = and <2 x i8> [[Y]], [[X]] -; CHECK-NEXT: [[R:%.*]] = icmp eq <2 x i8> [[W]], -; CHECK-NEXT: ret <2 x i1> [[R]] +; CHECK-NEXT: ret <2 x i1> zeroinitializer ; %C1 = or <2 x i8> %C, %y = sub <2 x i8> %x, %C1 @@ -18,11 +14,7 @@ define <2 x i1> @sub_XY_and_bit0_is_zero(<2 x i8> %x, <2 x i8> %C) nounwind { define i1 @sub_XY_xor_bit0_is_one(i8 %x, i8 %C) nounwind { ; CHECK-LABEL: @sub_XY_xor_bit0_is_one( -; CHECK-NEXT: [[C1:%.*]] = or i8 [[C:%.*]], 1 -; CHECK-NEXT: [[Y:%.*]] = sub i8 [[X:%.*]], [[C1]] -; CHECK-NEXT: [[W:%.*]] = xor i8 [[Y]], [[X]] -; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[W]], 10 -; CHECK-NEXT: ret i1 [[R]] +; CHECK-NEXT: ret i1 false ; %C1 = or i8 %C, 1 %y = sub i8 %x, %C1 @@ -33,11 +25,7 @@ define i1 @sub_XY_xor_bit0_is_one(i8 %x, i8 %C) nounwind { define i1 @sub_XY_or_bit0_is_one(i8 %x, i8 %C) nounwind { ; CHECK-LABEL: @sub_XY_or_bit0_is_one( -; CHECK-NEXT: [[C1:%.*]] = or i8 [[C:%.*]], 1 -; CHECK-NEXT: [[Y:%.*]] = sub i8 [[X:%.*]], [[C1]] -; CHECK-NEXT: [[W:%.*]] = or i8 [[Y]], [[X]] -; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[W]], 10 -; CHECK-NEXT: ret i1 [[R]] +; CHECK-NEXT: ret i1 false ; %C1 = or i8 %C, 1 %y = sub i8 %x, %C1 @@ -48,11 +36,7 @@ define i1 @sub_XY_or_bit0_is_one(i8 %x, i8 %C) nounwind { define i1 @sub_YX_and_bit0_is_zero(i8 %x, i8 %C) nounwind { ; CHECK-LABEL: @sub_YX_and_bit0_is_zero( -; CHECK-NEXT: [[C1:%.*]] = or i8 [[C:%.*]], 1 -; CHECK-NEXT: [[Y:%.*]] = sub i8 [[C1]], [[X:%.*]] -; CHECK-NEXT: [[W:%.*]] = and i8 [[Y]], [[X]] -; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[W]], -1 -; CHECK-NEXT: ret i1 [[R]] +; CHECK-NEXT: ret i1 false ; %C1 = or i8 %C, 1 %y = sub i8 %C1, %x @@ -63,11 +47,7 @@ define i1 @sub_YX_and_bit0_is_zero(i8 %x, i8 %C) nounwind { define <2 x i1> @sub_YX_xor_bit0_is_one(<2 x i8> %x, <2 x i8> %C) nounwind { ; CHECK-LABEL: @sub_YX_xor_bit0_is_one( -; CHECK-NEXT: [[C1:%.*]] = or <2 x i8> [[C:%.*]], -; CHECK-NEXT: [[Y:%.*]] = sub <2 x i8> [[C1]], [[X:%.*]] -; CHECK-NEXT: [[W:%.*]] = xor <2 x i8> [[Y]], [[X]] -; CHECK-NEXT: [[R:%.*]] = icmp eq <2 x i8> [[W]], -; CHECK-NEXT: ret <2 x i1> [[R]] +; CHECK-NEXT: ret <2 x i1> zeroinitializer ; %C1 = or <2 x i8> %C, %y = sub <2 x i8> %C1, %x @@ -78,11 +58,7 @@ define <2 x i1> @sub_YX_xor_bit0_is_one(<2 x i8> %x, <2 x i8> %C) nounwind { define i1 @sub_YX_or_bit0_is_one(i8 %x, i8 %C) nounwind { ; CHECK-LABEL: @sub_YX_or_bit0_is_one( -; CHECK-NEXT: [[C1:%.*]] = or i8 [[C:%.*]], 1 -; CHECK-NEXT: [[Y:%.*]] = sub i8 [[C1]], [[X:%.*]] -; CHECK-NEXT: [[W:%.*]] = or i8 [[Y]], [[X]] -; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[W]], 32 -; CHECK-NEXT: ret i1 [[R]] +; CHECK-NEXT: ret i1 false ; %C1 = or i8 %C, 1 %y = sub i8 %C1, %x @@ -93,11 +69,7 @@ define i1 @sub_YX_or_bit0_is_one(i8 %x, i8 %C) nounwind { define i1 @add_YX_xor_bit0_is_one(i8 %x, i8 %C) nounwind { ; CHECK-LABEL: @add_YX_xor_bit0_is_one( -; CHECK-NEXT: [[C1:%.*]] = or i8 [[C:%.*]], 1 -; CHECK-NEXT: [[Y:%.*]] = add i8 [[C1]], [[X:%.*]] -; CHECK-NEXT: [[W:%.*]] = xor i8 [[Y]], [[X]] -; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[W]], 32 -; CHECK-NEXT: ret i1 [[R]] +; CHECK-NEXT: ret i1 false ; %C1 = or i8 %C, 1 %y = add i8 %C1, %x @@ -108,11 +80,7 @@ define i1 @add_YX_xor_bit0_is_one(i8 %x, i8 %C) nounwind { define <2 x i1> @add_XY_or_bit0_is_one(<2 x i8> %x, <2 x i8> %C) nounwind { ; CHECK-LABEL: @add_XY_or_bit0_is_one( -; CHECK-NEXT: [[C1:%.*]] = or <2 x i8> [[C:%.*]], -; CHECK-NEXT: [[Y:%.*]] = add <2 x i8> [[C1]], [[X:%.*]] -; CHECK-NEXT: [[W:%.*]] = or <2 x i8> [[Y]], [[X]] -; CHECK-NEXT: [[R:%.*]] = icmp eq <2 x i8> [[W]], -; CHECK-NEXT: ret <2 x i1> [[R]] +; CHECK-NEXT: ret <2 x i1> zeroinitializer ; %C1 = or <2 x i8> %C, %y = add <2 x i8> %C1, %x