aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/IR/ConstantRange.cpp
diff options
context:
space:
mode:
authorYingwei Zheng <dtcxzyw2333@gmail.com>2023-11-06 15:59:50 +0800
committerGitHub <noreply@github.com>2023-11-06 15:59:50 +0800
commitb6deea1b53ae84806941c0a43e4f59d3aa40692a (patch)
tree6b839699da16deb8c5087701b2d51ed2924f6697 /llvm/lib/IR/ConstantRange.cpp
parenta07dbf1fb0f4ba36911233c82914a9ddf3eb4a09 (diff)
downloadllvm-b6deea1b53ae84806941c0a43e4f59d3aa40692a.zip
llvm-b6deea1b53ae84806941c0a43e4f59d3aa40692a.tar.gz
llvm-b6deea1b53ae84806941c0a43e4f59d3aa40692a.tar.bz2
[ConstantRange] Handle `Intrinsic::ctpop` (#68310)
This patch adds support for `Intrinsic::ctpop` in ConstantRange. It calculates the range in O(1) with the LCP-based method. Migrated from https://reviews.llvm.org/D153505.
Diffstat (limited to 'llvm/lib/IR/ConstantRange.cpp')
-rw-r--r--llvm/lib/IR/ConstantRange.cpp49
1 files changed, 49 insertions, 0 deletions
diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp
index 3d71b20..af93b69 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(!ConstantRange(Lower, Upper).isWrappedSet() &&
+ "Unexpected wrapped set.");
+ assert(Lower != Upper && "Unexpected empty set.");
+ unsigned BitWidth = Lower.getBitWidth();
+ 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 + 1));
+}
+
+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 (!isWrappedSet())
+ 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, Lower.countl_one()),
+ APInt(BitWidth, BitWidth + 1));
+ // Handle [0, Upper)
+ ConstantRange CR2 = getUnsignedPopCountRange(Zero, Upper);
+ return CR1.unionWith(CR2);
+}
+
ConstantRange::OverflowResult ConstantRange::unsignedAddMayOverflow(
const ConstantRange &Other) const {
if (isEmptySet() || Other.isEmptySet())