Skip to content

Commit 1550094

Browse files
committed
byte_extract lowering: also use a lower bound
We already limited extraction at an uppper bound, but when we know the offset we can also start as late as possible. For structs, for example, we now do not expand components that will be irrelevant to the final result.
1 parent ab1ad7f commit 1550094

File tree

1 file changed

+75
-7
lines changed

1 file changed

+75
-7
lines changed

src/solvers/lowering/byte_operators.cpp

Lines changed: 75 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Author: Daniel Kroening, kroening@kroening.com
2121
static exprt unpack_rec(
2222
const exprt &src,
2323
bool little_endian,
24+
const exprt &offset,
2425
const exprt &max_bytes,
2526
const namespacet &ns,
2627
bool unpack_byte_array = false);
@@ -31,6 +32,8 @@ static exprt unpack_rec(
3132
/// a constant value, otherwise we fail with an exception
3233
/// \param element_width: bit width of array/vector elements
3334
/// \param little_endian: true, iff assumed endianness is little-endian
35+
/// \param offset_bytes: if not nil, bytes prior to this offset will be filled
36+
/// with nil values
3437
/// \param max_bytes: if not nil, use as upper bound of the number of bytes to
3538
/// unpack
3639
/// \param ns: namespace for type lookups
@@ -40,6 +43,7 @@ static array_exprt unpack_array_vector(
4043
const exprt &src_size,
4144
const mp_integer &element_width,
4245
bool little_endian,
46+
const exprt &offset_bytes,
4347
const exprt &max_bytes,
4448
const namespacet &ns)
4549
{
@@ -51,6 +55,7 @@ static array_exprt unpack_array_vector(
5155
throw non_const_array_sizet(src.type(), max_bytes);
5256
}
5357

58+
exprt::operandst byte_operands;
5459
mp_integer first_element = 0;
5560

5661
// refine the number of elements to extract in case the element width is known
@@ -66,6 +71,17 @@ static array_exprt unpack_array_vector(
6671
// round up to nearest multiple of el_bytes
6772
max_elements = (*max_bytes_int + el_bytes - 1) / el_bytes;
6873
}
74+
75+
if(auto offset_bytes_int = numeric_cast<mp_integer>(offset_bytes))
76+
{
77+
// compute offset as number of elements
78+
first_element = *offset_bytes_int / el_bytes;
79+
// insert offset_bytes-many nil bytes into the output array
80+
*offset_bytes_int -= *offset_bytes_int % el_bytes;
81+
byte_operands.resize(
82+
numeric_cast_v<std::size_t>(*offset_bytes_int),
83+
from_integer(0, unsignedbv_typet(8)));
84+
}
6985
}
7086

7187
// the maximum number of bytes is an upper bound in case the size of the
@@ -76,7 +92,6 @@ static array_exprt unpack_array_vector(
7692

7793
const exprt src_simp = simplify_expr(src, ns);
7894

79-
exprt::operandst byte_operands;
8095
for(mp_integer i = first_element; i < *num_elements; ++i)
8196
{
8297
exprt element;
@@ -95,7 +110,8 @@ static array_exprt unpack_array_vector(
95110

96111
// recursively unpack each element until so that we eventually just have an
97112
// array of bytes left
98-
exprt sub = unpack_rec(element, little_endian, max_bytes, ns, true);
113+
exprt sub =
114+
unpack_rec(element, little_endian, nil_exprt(), max_bytes, ns, true);
99115
byte_operands.insert(
100116
byte_operands.end(), sub.operands().begin(), sub.operands().end());
101117
}
@@ -109,6 +125,8 @@ static array_exprt unpack_array_vector(
109125
/// Rewrite an object into its individual bytes.
110126
/// \param src: object to unpack
111127
/// \param little_endian: true, iff assumed endianness is little-endian
128+
/// \param offset_bytes: if not nil, bytes prior to this offset will be filled
129+
/// with nil values
112130
/// \param max_bytes: if not nil, use as upper bound of the number of bytes to
113131
/// unpack
114132
/// \param ns: namespace for type lookups
@@ -121,6 +139,7 @@ static array_exprt unpack_array_vector(
121139
static exprt unpack_rec(
122140
const exprt &src,
123141
bool little_endian,
142+
const exprt &offset_bytes,
124143
const exprt &max_bytes,
125144
const namespacet &ns,
126145
bool unpack_byte_array)
@@ -137,7 +156,13 @@ static exprt unpack_rec(
137156
return src;
138157

139158
return unpack_array_vector(
140-
src, array_type.size(), *element_width, little_endian, max_bytes, ns);
159+
src,
160+
array_type.size(),
161+
*element_width,
162+
little_endian,
163+
offset_bytes,
164+
max_bytes,
165+
ns);
141166
}
142167
else if(src.type().id() == ID_vector)
143168
{
@@ -151,13 +176,21 @@ static exprt unpack_rec(
151176
return src;
152177

153178
return unpack_array_vector(
154-
src, vector_type.size(), *element_width, little_endian, max_bytes, ns);
179+
src,
180+
vector_type.size(),
181+
*element_width,
182+
little_endian,
183+
offset_bytes,
184+
max_bytes,
185+
ns);
155186
}
156187
else if(ns.follow(src.type()).id()==ID_struct)
157188
{
158189
const struct_typet &struct_type=to_struct_type(ns.follow(src.type()));
159190
const struct_typet::componentst &components=struct_type.components();
160191

192+
mp_integer member_offset_bits = 0;
193+
161194
exprt::operandst byte_operands;
162195
for(const auto &comp : components)
163196
{
@@ -171,11 +204,43 @@ static exprt unpack_rec(
171204
throw non_byte_alignedt(struct_type, comp, *element_width);
172205
}
173206

207+
exprt offset_in_member = nil_exprt();
208+
auto offset_in_member_int = numeric_cast<mp_integer>(offset_bytes);
209+
exprt max_bytes_left = nil_exprt();
210+
auto max_bytes_left_int = numeric_cast<mp_integer>(max_bytes);
211+
212+
if(offset_in_member_int.has_value())
213+
{
214+
*offset_in_member_int -= member_offset_bits / 8;
215+
// if the offset is negative, offset_in_member remains nil, which has
216+
// the same effect as setting it to zero
217+
if(*offset_in_member_int >= 0)
218+
{
219+
offset_in_member =
220+
from_integer(*offset_in_member_int, offset_bytes.type());
221+
}
222+
}
223+
224+
if(max_bytes_left_int.has_value())
225+
{
226+
*max_bytes_left_int -= member_offset_bits / 8;
227+
if(*max_bytes_left_int >= 0)
228+
max_bytes_left = from_integer(*max_bytes_left_int, max_bytes.type());
229+
else
230+
break;
231+
}
232+
174233
member_exprt member(src, comp.get_name(), comp.type());
175-
exprt sub=unpack_rec(member, little_endian, max_bytes, ns, true);
234+
if(src.id() == ID_struct)
235+
simplify(member, ns);
236+
237+
exprt sub = unpack_rec(
238+
member, little_endian, offset_in_member, max_bytes_left, ns, true);
176239

177240
byte_operands.insert(
178241
byte_operands.end(), sub.operands().begin(), sub.operands().end());
242+
243+
member_offset_bits += *element_width;
179244
}
180245

181246
const std::size_t size = byte_operands.size();
@@ -295,9 +360,12 @@ exprt lower_byte_extract(const byte_extract_exprt &src, const namespacet &ns)
295360
typecast_exprt(src.offset(), upper_bound.type())),
296361
ns);
297362

363+
exprt lb = src.offset();
364+
if(!lb.is_constant())
365+
lb.make_nil();
366+
298367
byte_extract_exprt unpacked(src);
299-
unpacked.op()=
300-
unpack_rec(src.op(), little_endian, upper_bound, ns);
368+
unpacked.op() = unpack_rec(src.op(), little_endian, lb, upper_bound, ns);
301369

302370
if(src.type().id()==ID_array)
303371
{

0 commit comments

Comments
 (0)