@@ -8,6 +8,8 @@ Author: Daniel Kroening, kroening@kroening.com
88
99#include " bv_utils.h"
1010
11+ #include < util/arith_tools.h>
12+
1113#include < list>
1214#include < utility>
1315
@@ -1693,3 +1695,65 @@ bvt bv_utilst::verilog_bv_normal_bits(const bvt &src)
16931695
16941696 return even_bits;
16951697}
1698+
1699+ // / Symbolic implementation of popcount (count of 1 bits in a bit vector)
1700+ // / Based on the pop0 algorithm from Hacker's Delight
1701+ // / \param bv: The bit vector to count 1s in
1702+ // / \return A bit vector representing the count
1703+ bvt bv_utilst::popcount (const bvt &bv)
1704+ {
1705+ PRECONDITION (!bv.empty ());
1706+
1707+ // Determine the result width: log2(bv.size()) + 1
1708+ std::size_t log2 = address_bits (bv.size ());
1709+ CHECK_RETURN (log2 >= 1 );
1710+
1711+ // Start with the original bit vector
1712+ bvt x = bv;
1713+
1714+ // Apply the parallel bit counting algorithm from Hacker's Delight (pop0).
1715+ // The algorithm works by summing adjacent bit groups of increasing sizes.
1716+
1717+ // Iterate through the stages of the algorithm, doubling the field size each
1718+ // time
1719+ for (std::size_t stage = 0 ; stage < log2; ++stage)
1720+ {
1721+ std::size_t shift_amount = 1 << stage; // 1, 2, 4, 8, 16, ...
1722+ std::size_t field_size = 2 * shift_amount; // 2, 4, 8, 16, 32, ...
1723+
1724+ // Skip if the bit vector is smaller than the field size
1725+ if (x.size () <= shift_amount)
1726+ break ;
1727+
1728+ // Shift the bit vector
1729+ bvt x_shifted = shift (x, shiftt::SHIFT_LRIGHT, shift_amount);
1730+
1731+ // Create a mask with 'shift_amount' ones followed by 'shift_amount' zeros,
1732+ // repeated
1733+ bvt mask;
1734+ mask.reserve (x.size ());
1735+ for (std::size_t i = 0 ; i < x.size (); i++)
1736+ {
1737+ if ((i % field_size) < shift_amount)
1738+ mask.push_back (const_literal (true ));
1739+ else
1740+ mask.push_back (const_literal (false ));
1741+ }
1742+
1743+ // Apply the mask to both the original and shifted bit vectors
1744+ bvt masked_x, masked_shifted;
1745+ masked_x.reserve (x.size ());
1746+ masked_shifted.reserve (x.size ());
1747+
1748+ for (std::size_t i = 0 ; i < x.size (); i++)
1749+ {
1750+ masked_x.push_back (prop.land (x[i], mask[i]));
1751+ masked_shifted.push_back (prop.land (x_shifted[i], mask[i]));
1752+ }
1753+
1754+ // Add the masked vectors
1755+ x = add (masked_x, masked_shifted);
1756+ }
1757+
1758+ return x;
1759+ }
0 commit comments