Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions llvm/include/llvm/IR/ConstantRange.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
49 changes: 49 additions & 0 deletions llvm/lib/IR/ConstantRange.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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())
Expand Down
3 changes: 1 addition & 2 deletions llvm/test/Transforms/CorrelatedValuePropagation/range.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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
;
Expand Down
6 changes: 6 additions & 0 deletions llvm/unittests/IR/ConstantRangeTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down