[llvm] [ConstantRange] Handle `Intrinsic::ctpop` (PR #68310)

Yingwei Zheng via llvm-commits llvm-commits at lists.llvm.org
Sun Nov 5 08:41:55 PST 2023


https://github.com/dtcxzyw updated https://github.com/llvm/llvm-project/pull/68310

>From a54f0145f909603c4cd3af8df6ab54eab0f9c545 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Thu, 5 Oct 2023 21:48:04 +0800
Subject: [PATCH 1/3] [ConstantRange] Handle `Intrinsic::ctpop`

---
 llvm/include/llvm/IR/ConstantRange.h          |  3 ++
 llvm/lib/IR/ConstantRange.cpp                 | 49 +++++++++++++++++++
 .../CorrelatedValuePropagation/range.ll       |  3 +-
 llvm/unittests/IR/ConstantRangeTest.cpp       |  6 +++
 4 files changed, 59 insertions(+), 2 deletions(-)

diff --git a/llvm/include/llvm/IR/ConstantRange.h b/llvm/include/llvm/IR/ConstantRange.h
index ca36732e4e2e8c2..017f1f36d8a663e 100644
--- a/llvm/include/llvm/IR/ConstantRange.h
+++ b/llvm/include/llvm/IR/ConstantRange.h
@@ -530,6 +530,9 @@ class [[nodiscard]] ConstantRange {
   /// ignoring a possible zero value contained in the input range.
   ConstantRange ctlz(bool ZeroIsPoison = false) const;
 
+  /// Calculate ctpop range.
+  ConstantRange ctpop() const;
+
   /// Represents whether an operation on the given constant range is known to
   /// always or never overflow.
   enum class OverflowResult {
diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp
index 3d71b20f7e853e0..f00fb1f1b9f36cc 100644
--- a/llvm/lib/IR/ConstantRange.cpp
+++ b/llvm/lib/IR/ConstantRange.cpp
@@ -949,6 +949,7 @@ bool ConstantRange::isIntrinsicSupported(Intrinsic::ID IntrinsicID) {
   case Intrinsic::smax:
   case Intrinsic::abs:
   case Intrinsic::ctlz:
+  case Intrinsic::ctpop:
     return true;
   default:
     return false;
@@ -986,6 +987,8 @@ ConstantRange ConstantRange::intrinsic(Intrinsic::ID IntrinsicID,
     assert(ZeroIsPoison->getBitWidth() == 1 && "Must be boolean");
     return Ops[0].ctlz(ZeroIsPoison->getBoolValue());
   }
+  case Intrinsic::ctpop:
+    return Ops[0].ctpop();
   default:
     assert(!isIntrinsicSupported(IntrinsicID) && "Shouldn't be supported");
     llvm_unreachable("Unsupported intrinsic");
@@ -1736,6 +1739,52 @@ ConstantRange ConstantRange::ctlz(bool ZeroIsPoison) const {
                      APInt(getBitWidth(), getUnsignedMin().countl_zero() + 1));
 }
 
+static ConstantRange getUnsignedPopCountRange(const APInt &Lower,
+                                              const APInt &Upper) {
+  assert(Lower.ule(Upper) && "Unexpected wrapped set.");
+  unsigned BitWidth = Lower.getBitWidth();
+  if (Lower == Upper)
+    return ConstantRange::getEmpty(BitWidth);
+  if (Lower + 1 == Upper)
+    return ConstantRange(APInt(BitWidth, Lower.popcount()));
+
+  APInt Max = Upper - 1;
+  // Calculate longest common prefix.
+  unsigned LCPLength = (Lower ^ Max).countl_zero();
+  unsigned LCPPopCount = Lower.getHiBits(LCPLength).popcount();
+  // If Lower is {LCP, 000...}, the minimum is the popcount of LCP.
+  // Otherwise, the minimum is the popcount of LCP + 1.
+  unsigned MinBits =
+      LCPPopCount + (Lower.countr_zero() < BitWidth - LCPLength ? 1 : 0);
+  // If Max is {LCP, 111...}, the maximum is the popcount of LCP + (BitWidth -
+  // length of LCP).
+  // Otherwise, the minimum is the popcount of LCP + (BitWidth -
+  // length of LCP - 1).
+  unsigned MaxBits = LCPPopCount + (BitWidth - LCPLength) +
+                     (Max.countr_one() >= BitWidth - LCPLength ? 1 : 0);
+  return ConstantRange(APInt(BitWidth, MinBits), APInt(BitWidth, MaxBits));
+}
+
+ConstantRange ConstantRange::ctpop() const {
+  if (isEmptySet())
+    return getEmpty();
+
+  unsigned BitWidth = getBitWidth();
+  APInt Zero = APInt::getZero(BitWidth);
+  if (isFullSet()) {
+    return getNonEmpty(Zero, APInt(BitWidth, BitWidth + 1));
+  }
+  if (!isUpperWrapped()) {
+    return getUnsignedPopCountRange(getLower(), getUpper());
+  }
+  ConstantRange CR1 = ConstantRange(
+      APInt(BitWidth,
+            BitWidth - (getUnsignedMax() - getLower() + 1).logBase2()),
+      APInt(BitWidth, BitWidth + 1)); // [lower, intmax]
+  ConstantRange CR2 = getUnsignedPopCountRange(Zero, getUpper()); // [0, upper)
+  return CR1.unionWith(CR2);
+}
+
 ConstantRange::OverflowResult ConstantRange::unsignedAddMayOverflow(
     const ConstantRange &Other) const {
   if (isEmptySet() || Other.isEmptySet())
diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/range.ll b/llvm/test/Transforms/CorrelatedValuePropagation/range.ll
index 5c10fdcd2b49217..cf85753e59c8083 100644
--- a/llvm/test/Transforms/CorrelatedValuePropagation/range.ll
+++ b/llvm/test/Transforms/CorrelatedValuePropagation/range.ll
@@ -1085,8 +1085,7 @@ define i1 @ctpop_fold(i16 %x) {
 ; CHECK-NEXT:    br i1 [[CMP]], label [[IF:%.*]], label [[ELSE:%.*]]
 ; CHECK:       if:
 ; CHECK-NEXT:    [[CTPOP:%.*]] = call i16 @llvm.ctpop.i16(i16 [[X]])
-; CHECK-NEXT:    [[RES:%.*]] = icmp ule i16 [[CTPOP]], 8
-; CHECK-NEXT:    ret i1 [[RES]]
+; CHECK-NEXT:    ret i1 true
 ; CHECK:       else:
 ; CHECK-NEXT:    ret i1 true
 ;
diff --git a/llvm/unittests/IR/ConstantRangeTest.cpp b/llvm/unittests/IR/ConstantRangeTest.cpp
index 1cb358a26062ca5..12facfb22fb3c73 100644
--- a/llvm/unittests/IR/ConstantRangeTest.cpp
+++ b/llvm/unittests/IR/ConstantRangeTest.cpp
@@ -2438,6 +2438,12 @@ TEST_F(ConstantRangeTest, Ctlz) {
       });
 }
 
+TEST_F(ConstantRangeTest, Ctpop) {
+  TestUnaryOpExhaustive(
+      [](const ConstantRange &CR) { return CR.ctpop(); },
+      [](const APInt &N) { return APInt(N.getBitWidth(), N.popcount()); });
+}
+
 TEST_F(ConstantRangeTest, castOps) {
   ConstantRange A(APInt(16, 66), APInt(16, 128));
   ConstantRange FpToI8 = A.castOp(Instruction::FPToSI, 8);

>From 77efe2e7f38df9edd84c536e9142eecc4362fad0 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sat, 4 Nov 2023 21:55:38 +0800
Subject: [PATCH 2/3] fixup! [ConstantRange] Handle `Intrinsic::ctpop`

---
 llvm/lib/IR/ConstantRange.cpp | 30 +++++++++++++++---------------
 1 file changed, 15 insertions(+), 15 deletions(-)

diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp
index f00fb1f1b9f36cc..97cccdd05b0619f 100644
--- a/llvm/lib/IR/ConstantRange.cpp
+++ b/llvm/lib/IR/ConstantRange.cpp
@@ -1741,10 +1741,10 @@ ConstantRange ConstantRange::ctlz(bool ZeroIsPoison) const {
 
 static ConstantRange getUnsignedPopCountRange(const APInt &Lower,
                                               const APInt &Upper) {
-  assert(Lower.ule(Upper) && "Unexpected wrapped set.");
+  assert(!ConstantRange(Lower, Upper).isWrappedSet() &&
+         "Unexpected wrapped set.");
+  assert(Lower != Upper && "Unexpected empty set.");
   unsigned BitWidth = Lower.getBitWidth();
-  if (Lower == Upper)
-    return ConstantRange::getEmpty(BitWidth);
   if (Lower + 1 == Upper)
     return ConstantRange(APInt(BitWidth, Lower.popcount()));
 
@@ -1760,9 +1760,9 @@ static ConstantRange getUnsignedPopCountRange(const APInt &Lower,
   // length of LCP).
   // Otherwise, the minimum is the popcount of LCP + (BitWidth -
   // length of LCP - 1).
-  unsigned MaxBits = LCPPopCount + (BitWidth - LCPLength) +
-                     (Max.countr_one() >= BitWidth - LCPLength ? 1 : 0);
-  return ConstantRange(APInt(BitWidth, MinBits), APInt(BitWidth, MaxBits));
+  unsigned MaxBits = LCPPopCount + (BitWidth - LCPLength) -
+                     (Max.countr_one() < BitWidth - LCPLength ? 1 : 0);
+  return ConstantRange(APInt(BitWidth, MinBits), APInt(BitWidth, MaxBits + 1));
 }
 
 ConstantRange ConstantRange::ctpop() const {
@@ -1771,17 +1771,17 @@ ConstantRange ConstantRange::ctpop() const {
 
   unsigned BitWidth = getBitWidth();
   APInt Zero = APInt::getZero(BitWidth);
-  if (isFullSet()) {
+  if (isFullSet())
     return getNonEmpty(Zero, APInt(BitWidth, BitWidth + 1));
-  }
-  if (!isUpperWrapped()) {
+  if (!isWrappedSet())
     return getUnsignedPopCountRange(getLower(), getUpper());
-  }
-  ConstantRange CR1 = ConstantRange(
-      APInt(BitWidth,
-            BitWidth - (getUnsignedMax() - getLower() + 1).logBase2()),
-      APInt(BitWidth, BitWidth + 1)); // [lower, intmax]
-  ConstantRange CR2 = getUnsignedPopCountRange(Zero, getUpper()); // [0, upper)
+  // The range is wrapped. We decompose it into two ranges, [0, Upper) and
+  // [Lower, 0).
+  // Handle [Lower, 0) == [Lower, Max]
+  ConstantRange CR1 = ConstantRange(APInt(BitWidth, getLower().countl_one()),
+                                    APInt(BitWidth, BitWidth + 1));
+  // Handle [0, Upper)
+  ConstantRange CR2 = getUnsignedPopCountRange(Zero, getUpper());
   return CR1.unionWith(CR2);
 }
 

>From 898882c2b39ac56d6fa1fefe7e2689d3247627ee Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Mon, 6 Nov 2023 00:41:24 +0800
Subject: [PATCH 3/3] fixup! [ConstantRange] Handle `Intrinsic::ctpop`

Address comments.
---
 llvm/lib/IR/ConstantRange.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp
index 97cccdd05b0619f..af93b69a11c4dab 100644
--- a/llvm/lib/IR/ConstantRange.cpp
+++ b/llvm/lib/IR/ConstantRange.cpp
@@ -1774,14 +1774,14 @@ ConstantRange ConstantRange::ctpop() const {
   if (isFullSet())
     return getNonEmpty(Zero, APInt(BitWidth, BitWidth + 1));
   if (!isWrappedSet())
-    return getUnsignedPopCountRange(getLower(), getUpper());
+    return getUnsignedPopCountRange(Lower, Upper);
   // The range is wrapped. We decompose it into two ranges, [0, Upper) and
   // [Lower, 0).
   // Handle [Lower, 0) == [Lower, Max]
-  ConstantRange CR1 = ConstantRange(APInt(BitWidth, getLower().countl_one()),
+  ConstantRange CR1 = ConstantRange(APInt(BitWidth, Lower.countl_one()),
                                     APInt(BitWidth, BitWidth + 1));
   // Handle [0, Upper)
-  ConstantRange CR2 = getUnsignedPopCountRange(Zero, getUpper());
+  ConstantRange CR2 = getUnsignedPopCountRange(Zero, Upper);
   return CR1.unionWith(CR2);
 }
 



More information about the llvm-commits mailing list