[llvm] 23b4198 - [Support] Add KnownBits::icmp helpers.

Simon Pilgrim via llvm-commits llvm-commits at lists.llvm.org
Mon Jan 4 05:08:03 PST 2021


Author: Simon Pilgrim
Date: 2021-01-04T12:46:27Z
New Revision: 23b41986527a3fc5615480a8f7a0b0debd5fcef4

URL: https://github.com/llvm/llvm-project/commit/23b41986527a3fc5615480a8f7a0b0debd5fcef4
DIFF: https://github.com/llvm/llvm-project/commit/23b41986527a3fc5615480a8f7a0b0debd5fcef4.diff

LOG: [Support] Add KnownBits::icmp helpers.

Check if all possible values for a pair of knownbits give the same icmp result - these are based off the checks performed in InstCombineCompares.cpp and D86578.

Add exhaustive unit test coverage - a followup will update InstCombineCompares.cpp to use this.

Added: 
    

Modified: 
    llvm/include/llvm/Support/KnownBits.h
    llvm/lib/Support/KnownBits.cpp
    llvm/unittests/Support/KnownBitsTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Support/KnownBits.h b/llvm/include/llvm/Support/KnownBits.h
index ec88b9807174..edb771d659e2 100644
--- a/llvm/include/llvm/Support/KnownBits.h
+++ b/llvm/include/llvm/Support/KnownBits.h
@@ -15,6 +15,7 @@
 #define LLVM_SUPPORT_KNOWNBITS_H
 
 #include "llvm/ADT/APInt.h"
+#include "llvm/ADT/Optional.h"
 
 namespace llvm {
 
@@ -328,6 +329,36 @@ struct KnownBits {
   /// NOTE: RHS (shift amount) bitwidth doesn't need to be the same as LHS.
   static KnownBits ashr(const KnownBits &LHS, const KnownBits &RHS);
 
+  /// Determine if these known bits always give the same ICMP_EQ result.
+  static Optional<bool> eq(const KnownBits &LHS, const KnownBits &RHS);
+
+  /// Determine if these known bits always give the same ICMP_NE result.
+  static Optional<bool> ne(const KnownBits &LHS, const KnownBits &RHS);
+
+  /// Determine if these known bits always give the same ICMP_UGT result.
+  static Optional<bool> ugt(const KnownBits &LHS, const KnownBits &RHS);
+
+  /// Determine if these known bits always give the same ICMP_UGE result.
+  static Optional<bool> uge(const KnownBits &LHS, const KnownBits &RHS);
+
+  /// Determine if these known bits always give the same ICMP_ULT result.
+  static Optional<bool> ult(const KnownBits &LHS, const KnownBits &RHS);
+
+  /// Determine if these known bits always give the same ICMP_ULE result.
+  static Optional<bool> ule(const KnownBits &LHS, const KnownBits &RHS);
+
+  /// Determine if these known bits always give the same ICMP_SGT result.
+  static Optional<bool> sgt(const KnownBits &LHS, const KnownBits &RHS);
+
+  /// Determine if these known bits always give the same ICMP_SGE result.
+  static Optional<bool> sge(const KnownBits &LHS, const KnownBits &RHS);
+
+  /// Determine if these known bits always give the same ICMP_SLT result.
+  static Optional<bool> slt(const KnownBits &LHS, const KnownBits &RHS);
+
+  /// Determine if these known bits always give the same ICMP_SLE result.
+  static Optional<bool> sle(const KnownBits &LHS, const KnownBits &RHS);
+
   /// Insert the bits from a smaller known bits starting at bitPosition.
   void insertBits(const KnownBits &SubBits, unsigned BitPosition) {
     Zero.insertBits(SubBits.Zero, BitPosition);

diff  --git a/llvm/lib/Support/KnownBits.cpp b/llvm/lib/Support/KnownBits.cpp
index 2c25b7d9bac5..0147d21d153a 100644
--- a/llvm/lib/Support/KnownBits.cpp
+++ b/llvm/lib/Support/KnownBits.cpp
@@ -268,6 +268,75 @@ KnownBits KnownBits::ashr(const KnownBits &LHS, const KnownBits &RHS) {
   return Known;
 }
 
+Optional<bool> KnownBits::eq(const KnownBits &LHS, const KnownBits &RHS) {
+  if (LHS.isConstant() && RHS.isConstant())
+    return Optional<bool>(LHS.getConstant() == RHS.getConstant());
+  if (LHS.getMaxValue().ult(RHS.getMinValue()) ||
+      LHS.getMinValue().ugt(RHS.getMaxValue()))
+    return Optional<bool>(false);
+  if (LHS.One.intersects(RHS.Zero) || RHS.One.intersects(LHS.Zero))
+    return Optional<bool>(false);
+  return None;
+}
+
+Optional<bool> KnownBits::ne(const KnownBits &LHS, const KnownBits &RHS) {
+  if (Optional<bool> KnownEQ = eq(LHS, RHS))
+    return Optional<bool>(!KnownEQ.getValue());
+  return None;
+}
+
+Optional<bool> KnownBits::ugt(const KnownBits &LHS, const KnownBits &RHS) {
+  if (LHS.isConstant() && RHS.isConstant())
+    return Optional<bool>(LHS.getConstant().ugt(RHS.getConstant()));
+  // LHS >u RHS -> false if umax(LHS) <= umax(RHS)
+  if (LHS.getMaxValue().ule(RHS.getMinValue()))
+    return Optional<bool>(false);
+  // LHS >u RHS -> true if umin(LHS) > umax(RHS)
+  if (LHS.getMinValue().ugt(RHS.getMaxValue()))
+    return Optional<bool>(true);
+  return None;
+}
+
+Optional<bool> KnownBits::uge(const KnownBits &LHS, const KnownBits &RHS) {
+  if (Optional<bool> IsUGT = ugt(RHS, LHS))
+    return Optional<bool>(!IsUGT.getValue());
+  return None;
+}
+
+Optional<bool> KnownBits::ult(const KnownBits &LHS, const KnownBits &RHS) {
+  return ugt(RHS, LHS);
+}
+
+Optional<bool> KnownBits::ule(const KnownBits &LHS, const KnownBits &RHS) {
+  return uge(RHS, LHS);
+}
+
+Optional<bool> KnownBits::sgt(const KnownBits &LHS, const KnownBits &RHS) {
+  if (LHS.isConstant() && RHS.isConstant())
+    return Optional<bool>(LHS.getConstant().sgt(RHS.getConstant()));
+  // LHS >s RHS -> false if smax(LHS) <= smax(RHS)
+  if (LHS.getSignedMaxValue().sle(RHS.getSignedMinValue()))
+    return Optional<bool>(false);
+  // LHS >s RHS -> true if smin(LHS) > smax(RHS)
+  if (LHS.getSignedMinValue().sgt(RHS.getSignedMaxValue()))
+    return Optional<bool>(true);
+  return None;
+}
+
+Optional<bool> KnownBits::sge(const KnownBits &LHS, const KnownBits &RHS) {
+  if (Optional<bool> KnownSGT = sgt(RHS, LHS))
+    return Optional<bool>(!KnownSGT.getValue());
+  return None;
+}
+
+Optional<bool> KnownBits::slt(const KnownBits &LHS, const KnownBits &RHS) {
+  return sgt(RHS, LHS);
+}
+
+Optional<bool> KnownBits::sle(const KnownBits &LHS, const KnownBits &RHS) {
+  return sge(RHS, LHS);
+}
+
 KnownBits KnownBits::abs(bool IntMinIsPoison) const {
   // If the source's MSB is zero then we know the rest of the bits already.
   if (isNonNegative())

diff  --git a/llvm/unittests/Support/KnownBitsTest.cpp b/llvm/unittests/Support/KnownBitsTest.cpp
index 528a645ec51a..ba587a1e2f65 100644
--- a/llvm/unittests/Support/KnownBitsTest.cpp
+++ b/llvm/unittests/Support/KnownBitsTest.cpp
@@ -281,6 +281,93 @@ TEST(KnownBitsTest, UnaryExhaustive) {
   });
 }
 
+TEST(KnownBitsTest, ICmpExhaustive) {
+  unsigned Bits = 4;
+  ForeachKnownBits(Bits, [&](const KnownBits &Known1) {
+    ForeachKnownBits(Bits, [&](const KnownBits &Known2) {
+      bool AllEQ = true, NoneEQ = true;
+      bool AllNE = true, NoneNE = true;
+      bool AllUGT = true, NoneUGT = true;
+      bool AllUGE = true, NoneUGE = true;
+      bool AllULT = true, NoneULT = true;
+      bool AllULE = true, NoneULE = true;
+      bool AllSGT = true, NoneSGT = true;
+      bool AllSGE = true, NoneSGE = true;
+      bool AllSLT = true, NoneSLT = true;
+      bool AllSLE = true, NoneSLE = true;
+
+      ForeachNumInKnownBits(Known1, [&](const APInt &N1) {
+        ForeachNumInKnownBits(Known2, [&](const APInt &N2) {
+          AllEQ &= N1.eq(N2);
+          AllNE &= N1.ne(N2);
+          AllUGT &= N1.ugt(N2);
+          AllUGE &= N1.uge(N2);
+          AllULT &= N1.ult(N2);
+          AllULE &= N1.ule(N2);
+          AllSGT &= N1.sgt(N2);
+          AllSGE &= N1.sge(N2);
+          AllSLT &= N1.slt(N2);
+          AllSLE &= N1.sle(N2);
+          NoneEQ &= !N1.eq(N2);
+          NoneNE &= !N1.ne(N2);
+          NoneUGT &= !N1.ugt(N2);
+          NoneUGE &= !N1.uge(N2);
+          NoneULT &= !N1.ult(N2);
+          NoneULE &= !N1.ule(N2);
+          NoneSGT &= !N1.sgt(N2);
+          NoneSGE &= !N1.sge(N2);
+          NoneSLT &= !N1.slt(N2);
+          NoneSLE &= !N1.sle(N2);
+        });
+      });
+
+      Optional<bool> KnownEQ = KnownBits::eq(Known1, Known2);
+      Optional<bool> KnownNE = KnownBits::ne(Known1, Known2);
+      Optional<bool> KnownUGT = KnownBits::ugt(Known1, Known2);
+      Optional<bool> KnownUGE = KnownBits::uge(Known1, Known2);
+      Optional<bool> KnownULT = KnownBits::ult(Known1, Known2);
+      Optional<bool> KnownULE = KnownBits::ule(Known1, Known2);
+      Optional<bool> KnownSGT = KnownBits::sgt(Known1, Known2);
+      Optional<bool> KnownSGE = KnownBits::sge(Known1, Known2);
+      Optional<bool> KnownSLT = KnownBits::slt(Known1, Known2);
+      Optional<bool> KnownSLE = KnownBits::sle(Known1, Known2);
+
+      EXPECT_EQ(AllEQ || NoneEQ, KnownEQ.hasValue());
+      EXPECT_EQ(AllNE || NoneNE, KnownNE.hasValue());
+      EXPECT_EQ(AllUGT || NoneUGT, KnownUGT.hasValue());
+      EXPECT_EQ(AllUGE || NoneUGE, KnownUGE.hasValue());
+      EXPECT_EQ(AllULT || NoneULT, KnownULT.hasValue());
+      EXPECT_EQ(AllULE || NoneULE, KnownULE.hasValue());
+      EXPECT_EQ(AllSGT || NoneSGT, KnownSGT.hasValue());
+      EXPECT_EQ(AllSGE || NoneSGE, KnownSGE.hasValue());
+      EXPECT_EQ(AllSLT || NoneSLT, KnownSLT.hasValue());
+      EXPECT_EQ(AllSLE || NoneSLE, KnownSLE.hasValue());
+
+      EXPECT_EQ(AllEQ, KnownEQ.hasValue() && KnownEQ.getValue());
+      EXPECT_EQ(AllNE, KnownNE.hasValue() && KnownNE.getValue());
+      EXPECT_EQ(AllUGT, KnownUGT.hasValue() && KnownUGT.getValue());
+      EXPECT_EQ(AllUGE, KnownUGE.hasValue() && KnownUGE.getValue());
+      EXPECT_EQ(AllULT, KnownULT.hasValue() && KnownULT.getValue());
+      EXPECT_EQ(AllULE, KnownULE.hasValue() && KnownULE.getValue());
+      EXPECT_EQ(AllSGT, KnownSGT.hasValue() && KnownSGT.getValue());
+      EXPECT_EQ(AllSGE, KnownSGE.hasValue() && KnownSGE.getValue());
+      EXPECT_EQ(AllSLT, KnownSLT.hasValue() && KnownSLT.getValue());
+      EXPECT_EQ(AllSLE, KnownSLE.hasValue() && KnownSLE.getValue());
+
+      EXPECT_EQ(NoneEQ, KnownEQ.hasValue() && !KnownEQ.getValue());
+      EXPECT_EQ(NoneNE, KnownNE.hasValue() && !KnownNE.getValue());
+      EXPECT_EQ(NoneUGT, KnownUGT.hasValue() && !KnownUGT.getValue());
+      EXPECT_EQ(NoneUGE, KnownUGE.hasValue() && !KnownUGE.getValue());
+      EXPECT_EQ(NoneULT, KnownULT.hasValue() && !KnownULT.getValue());
+      EXPECT_EQ(NoneULE, KnownULE.hasValue() && !KnownULE.getValue());
+      EXPECT_EQ(NoneSGT, KnownSGT.hasValue() && !KnownSGT.getValue());
+      EXPECT_EQ(NoneSGE, KnownSGE.hasValue() && !KnownSGE.getValue());
+      EXPECT_EQ(NoneSLT, KnownSLT.hasValue() && !KnownSLT.getValue());
+      EXPECT_EQ(NoneSLE, KnownSLE.hasValue() && !KnownSLE.getValue());
+    });
+  });
+}
+
 TEST(KnownBitsTest, GetMinMaxVal) {
   unsigned Bits = 4;
   ForeachKnownBits(Bits, [&](const KnownBits &Known) {


        


More information about the llvm-commits mailing list