Skip to content

Commit 583faf1

Browse files
committed
Make lower_popcount a method of popcount_exprt
Expression lowering may be useful well outside the solvers/ context. Making it a method of the class being lowered also serves as a way of describing the semantics of the expression. This is mainly a refactoring, no changes in behaviour are intended.
1 parent 6c4d934 commit 583faf1

File tree

7 files changed

+59
-72
lines changed

7 files changed

+59
-72
lines changed

src/solvers/Makefile

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,6 @@ SRC = $(BOOLEFORCE_SRC) \
141141
floatbv/float_approximation.cpp \
142142
lowering/byte_operators.cpp \
143143
lowering/functions.cpp \
144-
lowering/popcount.cpp \
145144
bdd/miniBDD/miniBDD.cpp \
146145
prop/bdd_expr.cpp \
147146
prop/cover_goals.cpp \

src/solvers/flattening/boolbv.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ bvt boolbvt::convert_bitvector(const exprt &expr)
227227
else if(expr.id()==ID_power)
228228
return convert_power(to_binary_expr(expr));
229229
else if(expr.id() == ID_popcount)
230-
return convert_bv(lower_popcount(to_popcount_expr(expr), ns));
230+
return convert_bv(to_popcount_expr(expr).lower());
231231

232232
return conversion_failed(expr);
233233
}

src/solvers/lowering/expr_lowering.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ Author: Michael Tautschnig
1414
class byte_extract_exprt;
1515
class byte_update_exprt;
1616
class namespacet;
17-
class popcount_exprt;
1817

1918
/// Rewrite a byte extract expression to more fundamental operations.
2019
/// \param src: Byte extract expression
@@ -44,10 +43,4 @@ exprt lower_byte_operators(const exprt &src, const namespacet &ns);
4443

4544
bool has_byte_operator(const exprt &src);
4645

47-
/// Lower a popcount_exprt to arithmetic and logic expressions
48-
/// \param expr: Input expression to be translated
49-
/// \param ns: Namespace for type lookups
50-
/// \return Semantically equivalent expression
51-
exprt lower_popcount(const popcount_exprt &expr, const namespacet &ns);
52-
5346
#endif /* CPROVER_SOLVERS_LOWERING_EXPR_LOWERING_H */

src/solvers/lowering/popcount.cpp

Lines changed: 0 additions & 61 deletions
This file was deleted.

src/solvers/smt2/smt2_conv.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1984,8 +1984,7 @@ void smt2_convt::convert_expr(const exprt &expr)
19841984
}
19851985
else if(expr.id() == ID_popcount)
19861986
{
1987-
exprt lowered = lower_popcount(to_popcount_expr(expr), ns);
1988-
convert_expr(lowered);
1987+
convert_expr(to_popcount_expr(expr).lower());
19891988
}
19901989
else
19911990
INVARIANT_WITH_DIAGNOSTICS(

src/util/bitvector_expr.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,11 @@ Author: Daniel Kroening, [email protected]
99
#include "bitvector_expr.h"
1010

1111
#include "arith_tools.h"
12+
#include "bitvector_types.h"
1213
#include "mathematical_types.h"
14+
#include "namespace.h"
15+
#include "simplify_expr.h"
16+
#include "symbol_table.h"
1317

1418
shift_exprt::shift_exprt(
1519
exprt _src,
@@ -40,3 +44,52 @@ extractbits_exprt::extractbits_exprt(
4044
from_integer(_upper, integer_typet()),
4145
from_integer(_lower, integer_typet()));
4246
}
47+
48+
exprt popcount_exprt::lower() const
49+
{
50+
// Hacker's Delight, variant pop0:
51+
// x = (x & 0x55555555) + ((x >> 1) & 0x55555555);
52+
// x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
53+
// x = (x & 0x0F0F0F0F) + ((x >> 4) & 0x0F0F0F0F);
54+
// x = (x & 0x00FF00FF) + ((x >> 8) & 0x00FF00FF);
55+
// etc.
56+
// return x;
57+
// http://www.hackersdelight.org/permissions.htm
58+
59+
// make sure the operand width is a power of two
60+
exprt x = op();
61+
const auto x_width = to_bitvector_type(x.type()).get_width();
62+
CHECK_RETURN(x_width >= 1);
63+
const std::size_t bits = address_bits(x_width);
64+
const std::size_t new_width = numeric_cast_v<std::size_t>(power(2, bits));
65+
66+
const bool need_typecast =
67+
new_width > x_width || x.type().id() != ID_unsignedbv;
68+
69+
if(need_typecast)
70+
x = typecast_exprt(x, unsignedbv_typet(new_width));
71+
72+
// repeatedly compute x = (x & bitmask) + ((x >> shift) & bitmask)
73+
for(std::size_t shift = 1; shift < new_width; shift <<= 1)
74+
{
75+
// x >> shift
76+
lshr_exprt shifted_x(
77+
x, from_integer(shift, unsignedbv_typet(address_bits(shift) + 1)));
78+
// bitmask is a string of alternating shift-many bits starting from lsb set
79+
// to 1
80+
std::string bitstring;
81+
bitstring.reserve(new_width);
82+
for(std::size_t i = 0; i < new_width / (2 * shift); ++i)
83+
bitstring += std::string(shift, '0') + std::string(shift, '1');
84+
const mp_integer value = binary2integer(bitstring, false);
85+
const constant_exprt bitmask(integer2bvrep(value, new_width), x.type());
86+
// build the expression
87+
x = plus_exprt(bitand_exprt(x, bitmask), bitand_exprt(shifted_x, bitmask));
88+
}
89+
90+
// the result is restricted to the result type and simplified; use a dummy
91+
// symbol table here as there is no need for type lookups
92+
symbol_tablet symbol_table;
93+
namespacet ns(symbol_table);
94+
return simplify_expr(typecast_exprt{x, type()}, ns);
95+
}

src/util/bitvector_expr.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,10 @@ class popcount_exprt : public unary_exprt
641641
: unary_exprt(ID_popcount, _op, _op.type())
642642
{
643643
}
644+
645+
/// Lower a popcount_exprt to arithmetic and logic expressions.
646+
/// \return Semantically equivalent expression
647+
exprt lower() const;
644648
};
645649

646650
template <>

0 commit comments

Comments
 (0)