[llvm] 196d3e3 - Add logic for tracking lowbit of (and/xor/or X, (add/sub X, Odd))

Noah Goldstein via llvm-commits llvm-commits at lists.llvm.org
Thu Feb 23 17:52:28 PST 2023


Author: Noah Goldstein
Date: 2023-02-23T19:52:17-06:00
New Revision: 196d3e39653c66b6809680e2ae725f7a688f672f

URL: https://github.com/llvm/llvm-project/commit/196d3e39653c66b6809680e2ae725f7a688f672f
DIFF: https://github.com/llvm/llvm-project/commit/196d3e39653c66b6809680e2ae725f7a688f672f.diff

LOG: 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

Added: 
    

Modified: 
    llvm/lib/Analysis/ValueTracking.cpp
    llvm/test/Analysis/ValueTracking/knownbits-and-or-xor-lowbit.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 098af2640f44a..94ec3517bc0a2 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 6573ffe3aeb5a..3b5602bc44885 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:%.*]], <i8 9, i8 9>
-; 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]], <i8 -1, i8 -1>
-; CHECK-NEXT:    ret <2 x i1> [[R]]
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
 ;
   %C1 = or <2 x i8> %C, <i8 9, i8 9>
   %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:%.*]], <i8 1, i8 1>
-; 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]], <i8 12, i8 12>
-; CHECK-NEXT:    ret <2 x i1> [[R]]
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
 ;
   %C1 = or <2 x i8> %C, <i8 1, i8 1>
   %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:%.*]], <i8 1, i8 1>
-; 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]], <i8 90, i8 90>
-; CHECK-NEXT:    ret <2 x i1> [[R]]
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
 ;
   %C1 = or <2 x i8> %C, <i8 1, i8 1>
   %y = add <2 x i8> %C1, %x


        


More information about the llvm-commits mailing list