Skip to content

Commit 16fb637

Browse files
committed
Fix simplify_extractbit and simplify_extractbits
With hexadecimal coding of constants we need to use expr2bits/bits2expr to evaluate extractbits, and just the underlying get_bvrep_bit for extractbit. Also document these expressions to clarify their semantics with regard to endianness.
1 parent 4507761 commit 16fb637

File tree

3 files changed

+74
-23
lines changed

3 files changed

+74
-23
lines changed

src/util/simplify_expr_int.cpp

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Author: Daniel Kroening, [email protected]
1313
#include "arith_tools.h"
1414
#include "base_type.h"
1515
#include "bv_arithmetic.h"
16+
#include "byte_operators.h"
1617
#include "config.h"
1718
#include "expr_util.h"
1819
#include "fixedbv.h"
@@ -845,28 +846,20 @@ bool simplify_exprt::simplify_extractbit(exprt &expr)
845846

846847
const auto index_converted_to_int =
847848
numeric_cast<mp_integer>(extractbit_expr.index());
848-
if(!index_converted_to_int.has_value())
849+
if(!index_converted_to_int.has_value() || *index_converted_to_int < 0 ||
850+
*index_converted_to_int >= src_bit_width)
849851
{
850852
return true;
851853
}
852-
const mp_integer index_as_int = index_converted_to_int.value();
853-
if(!extractbit_expr.src().is_constant())
854-
return true;
855-
856-
if(index_as_int < 0 || index_as_int >= src_bit_width)
857-
return true;
858-
859-
const irep_idt &src_value =
860-
to_constant_expr(extractbit_expr.src()).get_value();
861854

862-
std::string src_value_as_string = id2string(src_value);
863-
864-
if(src_value_as_string.size() != src_bit_width)
855+
if(!extractbit_expr.src().is_constant())
865856
return true;
866857

867858
const bool bit =
868-
(src_value_as_string[src_bit_width -
869-
numeric_cast_v<std::size_t>(index_as_int) - 1] == '1');
859+
get_bvrep_bit(
860+
to_constant_expr(extractbit_expr.src()).get_value(),
861+
src_bit_width,
862+
numeric_cast_v<std::size_t>(*index_converted_to_int));
870863

871864
expr.make_bool(bit);
872865

@@ -1136,18 +1129,19 @@ bool simplify_exprt::simplify_extractbits(extractbits_exprt &expr)
11361129

11371130
if(expr.src().is_constant())
11381131
{
1139-
const irep_idt &value = to_constant_expr(expr.src()).get_value();
1132+
const auto svalue = expr2bits(expr.src(), true);
11401133

1141-
if(value.size() != *width)
1134+
if(!svalue.has_value() || svalue->size() != *width)
11421135
return true;
11431136

1144-
std::string svalue=id2string(value);
1145-
1146-
std::string extracted_value = svalue.substr(
1147-
numeric_cast_v<std::size_t>(*width - start - 1),
1137+
std::string extracted_value = svalue->substr(
1138+
numeric_cast_v<std::size_t>(end),
11481139
numeric_cast_v<std::size_t>(start - end + 1));
11491140

1150-
constant_exprt result(extracted_value, expr.type());
1141+
exprt result = bits2expr(extracted_value, expr.type(), true);
1142+
if(result.is_nil())
1143+
return true;
1144+
11511145
expr.swap(result);
11521146

11531147
return false;

src/util/std_expr.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3085,12 +3085,14 @@ class extractbit_exprt:public binary_predicate_exprt
30853085
{
30863086
}
30873087

3088+
/// Extract the \p _index-th least significant bit from \p _src.
30883089
extractbit_exprt(
30893090
const exprt &_src,
30903091
const exprt &_index):binary_predicate_exprt(_src, ID_extractbit, _index)
30913092
{
30923093
}
30933094

3095+
/// \copydoc extractbit_exprt(const exprt &, const exprt &)
30943096
extractbit_exprt(
30953097
const exprt &_src,
30963098
const std::size_t _index);
@@ -3161,7 +3163,11 @@ class extractbits_exprt:public exprt
31613163
operands().resize(3);
31623164
}
31633165

3164-
// the ordering upper-lower matches the SMT-LIB
3166+
/// Extract the bits [\p _lower .. \p _upper] from \p _src to produce a result
3167+
/// of type \p _type. Note that this specifies a closed interval, i.e., both
3168+
/// bits \p _lower and \p _upper are included. Indices count from the
3169+
/// least-significant bit, and are not affected by endianness.
3170+
/// The ordering upper-lower matches what SMT-LIB uses.
31653171
extractbits_exprt(
31663172
const exprt &_src,
31673173
const exprt &_upper,
@@ -3171,6 +3177,8 @@ class extractbits_exprt:public exprt
31713177
add_to_operands(_src, _upper, _lower);
31723178
}
31733179

3180+
/// \copydoc extractbits_exprt(const exprt &, const exprt &, const exprt &,
3181+
/// const typet &)
31743182
extractbits_exprt(
31753183
const exprt &_src,
31763184
const std::size_t _upper,

unit/util/simplify_expr.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,3 +106,52 @@ TEST_CASE("expr2bits and bits2expr respect bit order")
106106
simp.bits2expr(*be, unsignedbv_typet(32), false);
107107
REQUIRE(deadbeef == should_be_deadbeef2);
108108
}
109+
110+
TEST_CASE("Simplify extractbit")
111+
{
112+
// this test does require a proper architecture to be set so that byte extract
113+
// uses adequate endianness
114+
const cmdlinet cmdline;
115+
config.set(cmdline);
116+
117+
const symbol_tablet symbol_table;
118+
const namespacet ns(symbol_table);
119+
120+
// binary: 1101 1110 1010 1101 1011 1110 1110 1111
121+
// ^MSB LSB^
122+
// bit23^ bit4^
123+
// extractbit and extractbits use offsets with respect to the
124+
// least-significant bit, endianess does not impact them
125+
const exprt deadbeef = from_integer(0xdeadbeef, unsignedbv_typet(32));
126+
127+
exprt eb1 = extractbit_exprt(deadbeef, 4);
128+
bool unmodified = simplify(eb1, ns);
129+
130+
REQUIRE(!unmodified);
131+
REQUIRE(eb1 == false_exprt());
132+
133+
exprt eb2 = extractbit_exprt(deadbeef, 23);
134+
unmodified = simplify(eb2, ns);
135+
136+
REQUIRE(!unmodified);
137+
REQUIRE(eb2 == true_exprt());
138+
}
139+
140+
TEST_CASE("Simplify extractbits")
141+
{
142+
// this test does require a proper architecture to be set so that byte extract
143+
// uses adequate endianness
144+
const cmdlinet cmdline;
145+
config.set(cmdline);
146+
147+
const symbol_tablet symbol_table;
148+
const namespacet ns(symbol_table);
149+
150+
const exprt deadbeef = from_integer(0xdeadbeef, unsignedbv_typet(32));
151+
152+
exprt eb = extractbits_exprt(deadbeef, 15, 8, unsignedbv_typet(8));
153+
bool unmodified = simplify(eb, ns);
154+
155+
REQUIRE(!unmodified);
156+
REQUIRE(eb == from_integer(0xbe, unsignedbv_typet(8)));
157+
}

0 commit comments

Comments
 (0)