Skip to content

Commit aff6268

Browse files
authored
Merge pull request #8190 from diffblue/updatebit_exprt
introduce `update_bit_exprt`
2 parents 547b1a8 + 6925475 commit aff6268

File tree

10 files changed

+183
-4
lines changed

10 files changed

+183
-4
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_bit.cpp \
131132
flattening/boolbv_update_bits.cpp \
132133
flattening/boolbv_width.cpp \
133134
flattening/boolbv_with.cpp \

src/solvers/flattening/boolbv.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ bvt boolbvt::convert_bitvector(const exprt &expr)
109109
return convert_with(to_with_expr(expr));
110110
else if(expr.id()==ID_update)
111111
return convert_update(to_update_expr(expr));
112+
else if(expr.id() == ID_update_bit)
113+
return convert_update_bit(to_update_bit_expr(expr));
112114
else if(expr.id()==ID_case)
113115
return convert_case(expr);
114116
else if(expr.id()==ID_cond)

src/solvers/flattening/boolbv.h

Lines changed: 2 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_bit_exprt;
4243
class update_bits_exprt;
4344

4445
class boolbvt:public arrayst
@@ -177,6 +178,7 @@ class boolbvt:public arrayst
177178
virtual bvt convert_member(const member_exprt &expr);
178179
virtual bvt convert_with(const with_exprt &expr);
179180
virtual bvt convert_update(const update_exprt &);
181+
virtual bvt convert_update_bit(const update_bit_exprt &);
180182
virtual bvt convert_update_bits(const update_bits_exprt &);
181183
virtual bvt convert_case(const exprt &expr);
182184
virtual bvt convert_cond(const cond_exprt &);
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_bit(const update_bit_exprt &expr)
14+
{
15+
return convert_bv(expr.lower());
16+
}

src/solvers/flattening/boolbv_with.cpp

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,32 @@ bvt boolbvt::convert_with(const with_exprt &expr)
2222
type.id() == ID_bv || type.id() == ID_unsignedbv ||
2323
type.id() == ID_signedbv)
2424
{
25+
if(expr.operands().size() > 3)
26+
{
27+
std::size_t s = expr.operands().size();
28+
29+
// strip off the trailing two operands
30+
with_exprt tmp = expr;
31+
tmp.operands().resize(s - 2);
32+
33+
with_exprt new_with_expr(
34+
tmp, expr.operands()[s - 2], expr.operands().back());
35+
36+
// recursive call
37+
return convert_with(new_with_expr);
38+
}
39+
2540
PRECONDITION(expr.operands().size() == 3);
26-
return convert_bv(
27-
update_bits_exprt(expr.old(), expr.where(), expr.new_value()));
41+
if(expr.new_value().type().id() == ID_bool)
42+
{
43+
return convert_bv(
44+
update_bit_exprt(expr.old(), expr.where(), expr.new_value()));
45+
}
46+
else
47+
{
48+
return convert_bv(
49+
update_bits_exprt(expr.old(), expr.where(), expr.new_value()));
50+
}
2851
}
2952

3053
bvt bv = convert_bv(expr.old());

src/solvers/smt2/smt2_conv.cpp

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1685,6 +1685,10 @@ void smt2_convt::convert_expr(const exprt &expr)
16851685
{
16861686
convert_update(to_update_expr(expr));
16871687
}
1688+
else if(expr.id() == ID_update_bit)
1689+
{
1690+
convert_update_bit(to_update_bit_expr(expr));
1691+
}
16881692
else if(expr.id() == ID_update_bits)
16891693
{
16901694
convert_update_bits(to_update_bits_expr(expr));
@@ -4290,8 +4294,16 @@ void smt2_convt::convert_with(const with_exprt &expr)
42904294
expr_type.id()==ID_unsignedbv ||
42914295
expr_type.id()==ID_signedbv)
42924296
{
4293-
convert_update_bits(
4294-
update_bits_exprt(expr.old(), expr.where(), expr.new_value()));
4297+
if(expr.new_value().type().id() == ID_bool)
4298+
{
4299+
convert_update_bit(
4300+
update_bit_exprt(expr.old(), expr.where(), expr.new_value()));
4301+
}
4302+
else
4303+
{
4304+
convert_update_bits(
4305+
update_bits_exprt(expr.old(), expr.where(), expr.new_value()));
4306+
}
42954307
}
42964308
else
42974309
UNEXPECTEDCASE(
@@ -4306,6 +4318,11 @@ void smt2_convt::convert_update(const update_exprt &expr)
43064318
SMT2_TODO("smt2_convt::convert_update to be implemented");
43074319
}
43084320

4321+
void smt2_convt::convert_update_bit(const update_bit_exprt &expr)
4322+
{
4323+
return convert_expr(expr.lower());
4324+
}
4325+
43094326
void smt2_convt::convert_update_bits(const update_bits_exprt &expr)
43104327
{
43114328
return convert_expr(expr.lower());

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_bit_exprt;
3536
class update_bits_exprt;
3637

3738
class smt2_convt : public stack_decision_proceduret
@@ -150,6 +151,7 @@ class smt2_convt : public stack_decision_proceduret
150151

151152
void convert_with(const with_exprt &expr);
152153
void convert_update(const update_exprt &);
154+
void convert_update_bit(const update_bit_exprt &);
153155
void convert_update_bits(const update_bits_exprt &);
154156

155157
void convert_expr(const exprt &);

src/util/bitvector_expr.cpp

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

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

src/util/bitvector_expr.h

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,93 @@ 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_bit_exprt : public expr_protectedt
536+
{
537+
public:
538+
/// Replaces the bit [\p _index] from \p _src to produce a result of
539+
/// the same type as \p _src. The index counts from the
540+
/// least-significant bit. Updates outside of the range of \p _src
541+
/// yield an expression equal to \p _src.
542+
update_bit_exprt(exprt _src, exprt _index, exprt _new_value)
543+
: expr_protectedt(
544+
ID_update_bit,
545+
_src.type(),
546+
{_src, std::move(_index), std::move(_new_value)})
547+
{
548+
PRECONDITION(new_value().type().id() == ID_bool);
549+
}
550+
551+
update_bit_exprt(exprt _src, const std::size_t _index, exprt _new_value);
552+
553+
exprt &src()
554+
{
555+
return op0();
556+
}
557+
558+
exprt &index()
559+
{
560+
return op1();
561+
}
562+
563+
exprt &new_value()
564+
{
565+
return op2();
566+
}
567+
568+
const exprt &src() const
569+
{
570+
return op0();
571+
}
572+
573+
const exprt &index() const
574+
{
575+
return op1();
576+
}
577+
578+
const exprt &new_value() const
579+
{
580+
return op2();
581+
}
582+
583+
static void check(
584+
const exprt &expr,
585+
const validation_modet vm = validation_modet::INVARIANT)
586+
{
587+
validate_operands(expr, 3, "update_bit must have three operands");
588+
}
589+
590+
/// A lowering to masking, shifting, or.
591+
exprt lower() const;
592+
};
593+
594+
template <>
595+
inline bool can_cast_expr<update_bit_exprt>(const exprt &base)
596+
{
597+
return base.id() == ID_update_bit;
598+
}
599+
600+
/// \brief Cast an exprt to an \ref update_bit_exprt
601+
///
602+
/// \a expr must be known to be \ref update_bit_exprt.
603+
///
604+
/// \param expr: Source expression
605+
/// \return Object of type \ref update_bit_exprt
606+
inline const update_bit_exprt &to_update_bit_expr(const exprt &expr)
607+
{
608+
PRECONDITION(expr.id() == ID_update_bit);
609+
update_bit_exprt::check(expr);
610+
return static_cast<const update_bit_exprt &>(expr);
611+
}
612+
613+
/// \copydoc to_update_bit_expr(const exprt &)
614+
inline update_bit_exprt &to_update_bit_expr(exprt &expr)
615+
{
616+
PRECONDITION(expr.id() == ID_update_bit);
617+
update_bit_exprt::check(expr);
618+
return static_cast<update_bit_exprt &>(expr);
619+
}
620+
534621
/// \brief Replaces a sub-range of a bit-vector operand
535622
class update_bits_exprt : public expr_protectedt
536623
{

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_bit)
188189
IREP_ID_ONE(update_bits)
189190
IREP_ID_TWO(C_reference, #reference)
190191
IREP_ID_TWO(C_rvalue_reference, #rvalue_reference)

0 commit comments

Comments
 (0)