|
8 | 8 |
|
9 | 9 | #include "bv_utils.h" |
10 | 10 |
|
| 11 | +#include <util/arith_tools.h> |
| 12 | + |
11 | 13 | #include <list> |
12 | 14 | #include <utility> |
13 | 15 |
|
@@ -1644,3 +1646,65 @@ bvt bv_utilst::verilog_bv_normal_bits(const bvt &src) |
1644 | 1646 |
|
1645 | 1647 | return even_bits; |
1646 | 1648 | } |
| 1649 | + |
| 1650 | +/// Symbolic implementation of popcount (count of 1 bits in a bit vector) |
| 1651 | +/// Based on the pop0 algorithm from Hacker's Delight |
| 1652 | +/// \param bv: The bit vector to count 1s in |
| 1653 | +/// \return A bit vector representing the count |
| 1654 | +bvt bv_utilst::popcount(const bvt &bv) |
| 1655 | +{ |
| 1656 | + PRECONDITION(!bv.empty()); |
| 1657 | + |
| 1658 | + // Determine the result width: log2(bv.size()) + 1 |
| 1659 | + std::size_t log2 = address_bits(bv.size()); |
| 1660 | + CHECK_RETURN(log2 >= 1); |
| 1661 | + |
| 1662 | + // Start with the original bit vector |
| 1663 | + bvt x = bv; |
| 1664 | + |
| 1665 | + // Apply the parallel bit counting algorithm from Hacker's Delight (pop0). |
| 1666 | + // The algorithm works by summing adjacent bit groups of increasing sizes. |
| 1667 | + |
| 1668 | + // Iterate through the stages of the algorithm, doubling the field size each |
| 1669 | + // time |
| 1670 | + for(std::size_t stage = 0; stage < log2; ++stage) |
| 1671 | + { |
| 1672 | + std::size_t shift_amount = 1 << stage; // 1, 2, 4, 8, 16, ... |
| 1673 | + std::size_t field_size = 2 * shift_amount; // 2, 4, 8, 16, 32, ... |
| 1674 | + |
| 1675 | + // Skip if the bit vector is smaller than the field size |
| 1676 | + if(x.size() <= shift_amount) |
| 1677 | + break; |
| 1678 | + |
| 1679 | + // Shift the bit vector |
| 1680 | + bvt x_shifted = shift(x, shiftt::SHIFT_LRIGHT, shift_amount); |
| 1681 | + |
| 1682 | + // Create a mask with 'shift_amount' ones followed by 'shift_amount' zeros, |
| 1683 | + // repeated |
| 1684 | + bvt mask; |
| 1685 | + mask.reserve(x.size()); |
| 1686 | + for(std::size_t i = 0; i < x.size(); i++) |
| 1687 | + { |
| 1688 | + if((i % field_size) < shift_amount) |
| 1689 | + mask.push_back(const_literal(true)); |
| 1690 | + else |
| 1691 | + mask.push_back(const_literal(false)); |
| 1692 | + } |
| 1693 | + |
| 1694 | + // Apply the mask to both the original and shifted bit vectors |
| 1695 | + bvt masked_x, masked_shifted; |
| 1696 | + masked_x.reserve(x.size()); |
| 1697 | + masked_shifted.reserve(x.size()); |
| 1698 | + |
| 1699 | + for(std::size_t i = 0; i < x.size(); i++) |
| 1700 | + { |
| 1701 | + masked_x.push_back(prop.land(x[i], mask[i])); |
| 1702 | + masked_shifted.push_back(prop.land(x_shifted[i], mask[i])); |
| 1703 | + } |
| 1704 | + |
| 1705 | + // Add the masked vectors |
| 1706 | + x = add(masked_x, masked_shifted); |
| 1707 | + } |
| 1708 | + |
| 1709 | + return x; |
| 1710 | +} |
0 commit comments