Skip to content

Commit 1371538

Browse files
committed
introduce update_bits_exprt
This introduces update_bits_exprt, which allows replacing parts of a bit-vector identified by a (potentially variable) index by a given bit-vector. This supersedes with_exprt in the case of single-bit operands.
1 parent 24b2947 commit 1371538

File tree

8 files changed

+151
-41
lines changed

8 files changed

+151
-41
lines changed

src/solvers/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ SRC = $(BOOLEFORCE_SRC) \
128128
flattening/boolbv_unary_minus.cpp \
129129
flattening/boolbv_union.cpp \
130130
flattening/boolbv_update.cpp \
131+
flattening/boolbv_update_bits.cpp \
131132
flattening/boolbv_width.cpp \
132133
flattening/boolbv_with.cpp \
133134
flattening/bv_dimacs.cpp \

src/solvers/flattening/boolbv.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ class overflow_result_exprt;
3939
class replication_exprt;
4040
class unary_overflow_exprt;
4141
class union_typet;
42+
class update_bits_exprt;
4243

4344
class boolbvt:public arrayst
4445
{
@@ -176,6 +177,7 @@ class boolbvt:public arrayst
176177
virtual bvt convert_member(const member_exprt &expr);
177178
virtual bvt convert_with(const with_exprt &expr);
178179
virtual bvt convert_update(const update_exprt &);
180+
virtual bvt convert_update_bits(const update_bits_exprt &);
179181
virtual bvt convert_case(const exprt &expr);
180182
virtual bvt convert_cond(const cond_exprt &);
181183
virtual bvt convert_shift(const binary_exprt &expr);
@@ -196,6 +198,8 @@ class boolbvt:public arrayst
196198
virtual bvt convert_saturating_add_sub(const binary_exprt &expr);
197199
virtual bvt convert_overflow_result(const overflow_result_exprt &expr);
198200

201+
bvt convert_update_bits(bvt src, const exprt &index, const bvt &new_value);
202+
199203
void convert_with(
200204
const typet &type,
201205
const exprt &where,
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/*******************************************************************\
2+
3+
Module:
4+
5+
Author: Daniel Kroening, [email protected]
6+
7+
\*******************************************************************/
8+
9+
#include <util/bitvector_expr.h>
10+
11+
#include "boolbv.h"
12+
13+
bvt boolbvt::convert_update_bits(const update_bits_exprt &expr)
14+
{
15+
return convert_bv(expr.lower());
16+
}

src/solvers/smt2/smt2_conv.cpp

Lines changed: 11 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1683,6 +1683,10 @@ void smt2_convt::convert_expr(const exprt &expr)
16831683
{
16841684
convert_update(to_update_expr(expr));
16851685
}
1686+
else if(expr.id() == ID_update_bits)
1687+
{
1688+
convert_update_bits(to_update_bits_expr(expr));
1689+
}
16861690
else if(expr.id() == ID_object_address)
16871691
{
16881692
out << "(object-address ";
@@ -4283,47 +4287,8 @@ void smt2_convt::convert_with(const with_exprt &expr)
42834287
expr_type.id()==ID_unsignedbv ||
42844288
expr_type.id()==ID_signedbv)
42854289
{
4286-
// Update bits in a bit-vector. We will use masking and shifts.
4287-
// TODO: SMT2-ify
4288-
SMT2_TODO("SMT2-ify");
4289-
4290-
#if 0
4291-
std::size_t total_width=boolbv_width(expr_type);
4292-
4293-
const exprt &index=expr.operands()[1];
4294-
const exprt &value=expr.operands()[2];
4295-
4296-
std::size_t value_width=boolbv_width(value.type());
4297-
4298-
typecast_exprt index_tc(index, expr_type);
4299-
4300-
out << "(bvor ";
4301-
out << "(band ";
4302-
4303-
// the mask to get rid of the old bits
4304-
out << " (bvnot (bvshl";
4305-
4306-
out << " (concat";
4307-
out << " (repeat[" << total_width-value_width << "] bv0[1])";
4308-
out << " (repeat[" << value_width << "] bv1[1])";
4309-
out << ")"; // concat
4310-
4311-
// shift it to the index
4312-
convert_expr(index_tc);
4313-
out << "))"; // bvshl, bvot
4314-
4315-
out << ")"; // bvand
4316-
4317-
// the new value
4318-
out << " (bvshl ";
4319-
convert_expr(value);
4320-
4321-
// shift it to the index
4322-
convert_expr(index_tc);
4323-
out << ")"; // bvshl
4324-
4325-
out << ")"; // bvor
4326-
#endif
4290+
convert_update_bits(
4291+
update_bits_exprt(expr.old(), expr.where(), expr.new_value()));
43274292
}
43284293
else
43294294
UNEXPECTEDCASE(
@@ -4338,6 +4303,11 @@ void smt2_convt::convert_update(const update_exprt &expr)
43384303
SMT2_TODO("smt2_convt::convert_update to be implemented");
43394304
}
43404305

4306+
void smt2_convt::convert_update_bits(const update_bits_exprt &expr)
4307+
{
4308+
return convert_expr(expr.lower());
4309+
}
4310+
43414311
void smt2_convt::convert_index(const index_exprt &expr)
43424312
{
43434313
const typet &array_op_type = expr.array().type();

src/solvers/smt2/smt2_conv.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ Author: Daniel Kroening, [email protected]
3232
class floatbv_typecast_exprt;
3333
class ieee_float_op_exprt;
3434
class union_typet;
35+
class update_bits_exprt;
3536

3637
class smt2_convt : public stack_decision_proceduret
3738
{
@@ -149,6 +150,7 @@ class smt2_convt : public stack_decision_proceduret
149150

150151
void convert_with(const with_exprt &expr);
151152
void convert_update(const update_exprt &);
153+
void convert_update_bits(const update_bits_exprt &);
152154

153155
void convert_expr(const exprt &);
154156
void convert_type(const typet &);

src/util/bitvector_expr.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,36 @@ extractbits_exprt::extractbits_exprt(
4242
from_integer(_lower, integer_typet()));
4343
}
4444

45+
exprt update_bits_exprt::lower() const
46+
{
47+
const auto width = to_bitvector_type(type()).get_width();
48+
const auto new_value_width =
49+
to_bitvector_type(new_value().type()).get_width();
50+
auto src_bv_type = bv_typet(width);
51+
52+
// build a mask 1...1 0...0
53+
auto mask_bv = make_bvrep(width, [new_value_width](std::size_t index) {
54+
return index >= new_value_width;
55+
});
56+
auto mask_expr = constant_exprt(mask_bv, src_bv_type);
57+
58+
// shift the mask by the index
59+
auto mask_shifted = shl_exprt(mask_expr, index());
60+
61+
auto src_masked =
62+
bitand_exprt(typecast_exprt(src(), src_bv_type), mask_shifted);
63+
64+
// zero-extend or shrink the replacement bits to match src
65+
auto new_value_casted = typecast_exprt(new_value(), src_bv_type);
66+
67+
// shift the replacement bits
68+
auto new_value_shifted = shl_exprt(new_value_casted, index());
69+
70+
// or the masked src and the shifted replacement bits
71+
return typecast_exprt(
72+
bitor_exprt(src_masked, new_value_shifted), src().type());
73+
}
74+
4575
exprt popcount_exprt::lower() const
4676
{
4777
// Hacker's Delight, variant pop0:

src/util/bitvector_expr.h

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,92 @@ inline extractbits_exprt &to_extractbits_expr(exprt &expr)
531531
return ret;
532532
}
533533

534+
/// \brief Replaces a sub-range of a bit-vector operand
535+
class update_bits_exprt : public expr_protectedt
536+
{
537+
public:
538+
/// Replace the bits [\p _index .. \p _index + size] from \p _src
539+
/// where size is the width of \p _new_value to produce a result of
540+
/// the same type as \p _src. The index counts from the
541+
/// least-significant bit.
542+
update_bits_exprt(exprt _src, exprt _index, exprt _new_value)
543+
: expr_protectedt(
544+
ID_update_bits,
545+
_src.type(),
546+
{_src, std::move(_index), std::move(_new_value)})
547+
{
548+
}
549+
550+
update_bits_exprt(exprt _src, const std::size_t _index, exprt _new_value);
551+
552+
exprt &src()
553+
{
554+
return op0();
555+
}
556+
557+
exprt &index()
558+
{
559+
return op1();
560+
}
561+
562+
exprt &new_value()
563+
{
564+
return op2();
565+
}
566+
567+
const exprt &src() const
568+
{
569+
return op0();
570+
}
571+
572+
const exprt &index() const
573+
{
574+
return op1();
575+
}
576+
577+
const exprt &new_value() const
578+
{
579+
return op2();
580+
}
581+
582+
static void check(
583+
const exprt &expr,
584+
const validation_modet vm = validation_modet::INVARIANT)
585+
{
586+
validate_operands(expr, 3, "update_bits must have three operands");
587+
}
588+
589+
/// A lowering to masking, shifting, or.
590+
exprt lower() const;
591+
};
592+
593+
template <>
594+
inline bool can_cast_expr<update_bits_exprt>(const exprt &base)
595+
{
596+
return base.id() == ID_update_bits;
597+
}
598+
599+
/// \brief Cast an exprt to an \ref update_bits_exprt
600+
///
601+
/// \a expr must be known to be \ref update_bits_exprt.
602+
///
603+
/// \param expr: Source expression
604+
/// \return Object of type \ref update_bits_exprt
605+
inline const update_bits_exprt &to_update_bits_expr(const exprt &expr)
606+
{
607+
PRECONDITION(expr.id() == ID_update_bits);
608+
update_bits_exprt::check(expr);
609+
return static_cast<const update_bits_exprt &>(expr);
610+
}
611+
612+
/// \copydoc to_update_bits_expr(const exprt &)
613+
inline update_bits_exprt &to_update_bits_expr(exprt &expr)
614+
{
615+
PRECONDITION(expr.id() == ID_update_bits);
616+
update_bits_exprt::check(expr);
617+
return static_cast<update_bits_exprt &>(expr);
618+
}
619+
534620
/// \brief Bit-vector replication
535621
class replication_exprt : public binary_exprt
536622
{

src/util/irep_ids.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ IREP_ID_ONE(exists)
185185
IREP_ID_ONE(repeat)
186186
IREP_ID_ONE(extractbit)
187187
IREP_ID_ONE(extractbits)
188+
IREP_ID_ONE(update_bits)
188189
IREP_ID_TWO(C_reference, #reference)
189190
IREP_ID_TWO(C_rvalue_reference, #rvalue_reference)
190191
IREP_ID_ONE(true)

0 commit comments

Comments
 (0)