Skip to content

Commit 8b1b4f8

Browse files
allightcopybara-github
authored andcommitted
Add helpers to determine required bit-width for intervals
Include support for if the bits are interpreted as signed and unsigned values. PiperOrigin-RevId: 645435596
1 parent a8eeed3 commit 8b1b4f8

File tree

3 files changed

+67
-0
lines changed

3 files changed

+67
-0
lines changed

xls/ir/interval_ops.cc

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -964,4 +964,38 @@ IntervalSet OneHot(const IntervalSet& val, LsbOrMsb lsb_or_msb,
964964
return FromTernary(res, max_interval_bits);
965965
}
966966

967+
int64_t MinimumBitCount(const IntervalSet& a) {
968+
if (a.IsEmpty()) {
969+
return 0;
970+
}
971+
return a.BitCount() - a.UpperBound()->CountLeadingZeros();
972+
}
973+
974+
int64_t MinimumSignedBitCount(const IntervalSet& a) {
975+
// Handle the extreme cases manually. No values or only the zero value are a
976+
// 0-bit integer.
977+
if (a.IsEmpty() || (a.GetPreciseValue() && a.GetPreciseValue()->IsZero())) {
978+
return 0;
979+
}
980+
if (a.Covers(Bits::MinSigned(a.BitCount())) ||
981+
a.Covers(Bits::MaxSigned(a.BitCount()))) {
982+
return a.BitCount();
983+
}
984+
IntervalSet positive = IntervalSet::Intersect(
985+
a, IntervalSet::Of({Interval::Closed(SBits(0, a.BitCount()),
986+
Bits::MaxSigned(a.BitCount()))}));
987+
// NB Intervals are unsigned and sbits are represented 2s complement so -1 is
988+
// the highest value possible in this bit-width. MinSigned is the next value
989+
// after MaxSigned in 2s complement representation.
990+
IntervalSet negative = IntervalSet::Intersect(
991+
a, IntervalSet::Of({Interval::Closed(Bits::MinSigned(a.BitCount()),
992+
SBits(-1, a.BitCount()))}));
993+
return std::max(positive.IsEmpty() ? 0 : MinimumBitCount(positive),
994+
negative.IsEmpty()
995+
? 0
996+
: (negative.BitCount() -
997+
negative.LowerBound()->CountLeadingOnes())) +
998+
1;
999+
}
1000+
9671001
} // namespace xls::interval_ops

xls/ir/interval_ops.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,12 @@ KnownBits ExtractKnownBits(const IntervalSet& intervals,
7979
// much distance is between 2 intervals might provide better results.
8080
IntervalSet MinimizeIntervals(IntervalSet interval_set, int64_t size);
8181

82+
// How many bits are needed to cover all values in the interval.
83+
int64_t MinimumBitCount(const IntervalSet& a);
84+
85+
// How many bits are needed to cover all *signed* integer values in the range.
86+
int64_t MinimumSignedBitCount(const IntervalSet& a);
87+
8288
// Arithmetic
8389
IntervalSet Add(const IntervalSet& a, const IntervalSet& b);
8490
IntervalSet Sub(const IntervalSet& a, const IntervalSet& b);

xls/ir/interval_ops_test.cc

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,15 @@ TEST(IntervalOpsTest, MiddleOutTernary) {
106106
EXPECT_EQ(known, expected);
107107
}
108108

109+
IntervalSet FromSignedRanges(
110+
absl::Span<std::pair<int64_t, int64_t> const> ranges, int64_t bits) {
111+
IntervalSet res(bits);
112+
for (const auto& [l, h] : ranges) {
113+
res.AddInterval(Interval::Closed(SBits(l, bits), SBits(h, bits)));
114+
}
115+
res.Normalize();
116+
return res;
117+
}
109118
IntervalSet FromRanges(absl::Span<std::pair<int64_t, int64_t> const> ranges,
110119
int64_t bits) {
111120
IntervalSet res(bits);
@@ -741,6 +750,24 @@ void UGtZ3Fuzz(absl::Span<std::pair<int64_t, int64_t> const> lhs,
741750
FUZZ_TEST(IntervalOpsTest, UGtZ3Fuzz)
742751
.WithDomains(IntervalDomain(8), IntervalDomain(8));
743752

753+
TEST(IntervalOpsTest, MinimumBitCount) {
754+
EXPECT_EQ(MinimumBitCount(IntervalSet(32)), 0);
755+
EXPECT_EQ(MinimumBitCount(IntervalSet::Precise(UBits(0, 32))), 0);
756+
EXPECT_EQ(MinimumBitCount(IntervalSet::Precise(UBits(32, 32))), 6);
757+
EXPECT_EQ(MinimumBitCount(FromRanges({{0, 3}, {4, 5}, {30, 33}}, 32)), 6);
758+
}
759+
760+
TEST(IntervalOpsTest, MinimumSignedBitCount) {
761+
EXPECT_EQ(MinimumSignedBitCount(IntervalSet(32)), 0);
762+
EXPECT_EQ(MinimumSignedBitCount(IntervalSet::Precise(UBits(0, 32))), 0);
763+
EXPECT_EQ(MinimumSignedBitCount(IntervalSet::Precise(UBits(32, 32))), 7);
764+
EXPECT_EQ(MinimumSignedBitCount(IntervalSet::Precise(SBits(-33, 32))), 7);
765+
EXPECT_EQ(MinimumSignedBitCount(FromSignedRanges({{-1, 0}}, 32)), 1);
766+
EXPECT_EQ(MinimumSignedBitCount(
767+
FromSignedRanges({{0, 3}, {4, 5}, {30, 33}, {-34, -2}}, 32)),
768+
7);
769+
}
770+
744771
TEST(MinimizeIntervalsTest, PrefersEarlyIntervals) {
745772
// All 32 6-bit [0, 63] even numbers.
746773
IntervalSet even_numbers =

0 commit comments

Comments
 (0)