Skip to content

Commit 5884421

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 54cce5a commit 5884421

File tree

1 file changed

+55
-4
lines changed

1 file changed

+55
-4
lines changed

src/solvers/lowering/byte_operators.cpp

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Author: Daniel Kroening, [email protected]
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);
@@ -30,6 +31,7 @@ static exprt unpack_rec(
3031
/// \param src_size: array/vector size
3132
/// \param element_width: bit width of array/vector elements
3233
/// \param little_endian: true, iff assumed endianness is little-endian
34+
/// \param offset: if not nil, use as lower bound for non-nil bytes to return
3335
/// \param max_bytes: if not nil, use as upper bound of the number of bytes to
3436
/// unpack
3537
/// \param ns: namespace for type lookups
@@ -39,6 +41,7 @@ static void unpack_array_vector(
3941
const exprt &src_size,
4042
const mp_integer &element_width,
4143
bool little_endian,
44+
const exprt &offset,
4245
const exprt &max_bytes,
4346
const namespacet &ns,
4447
array_exprt &dest_array)
@@ -67,6 +70,17 @@ static void unpack_array_vector(
6770

6871
*max_bytes_int /= el_bytes;
6972
}
73+
74+
if(auto offset_bytes = numeric_cast<mp_integer>(offset))
75+
{
76+
// compute offset as number of elements
77+
first_element = *offset_bytes / el_bytes;
78+
// insert offset_bytes-many nil bytes into the output array
79+
*offset_bytes -= *offset_bytes % el_bytes;
80+
dest_array.operands().resize(
81+
numeric_cast_v<std::size_t>(*offset_bytes),
82+
from_integer(0, unsignedbv_typet(8)));
83+
}
7084
}
7185

7286
// the maximum number of bytes is an upper bound in case the size of the
@@ -91,7 +105,8 @@ static void unpack_array_vector(
91105
element = src_simp.operands()[index_int];
92106
}
93107

94-
exprt sub = unpack_rec(element, little_endian, max_bytes, ns, true);
108+
exprt sub =
109+
unpack_rec(element, little_endian, nil_exprt(), max_bytes, ns, true);
95110
dest_array.operands().insert(
96111
dest_array.operands().end(),
97112
sub.operands().begin(),
@@ -102,6 +117,7 @@ static void unpack_array_vector(
102117
/// rewrite an object into its individual bytes
103118
/// \param src: object to unpack
104119
/// \param little_endian: true, iff assumed endianness is little-endian
120+
/// \param offset: if not nil, use as lower bound for non-nil bytes to return
105121
/// \param max_bytes: if not nil, use as upper bound of the number of bytes to
106122
/// unpack
107123
/// \param ns: namespace for type lookups
@@ -114,6 +130,7 @@ static void unpack_array_vector(
114130
static exprt unpack_rec(
115131
const exprt &src,
116132
bool little_endian,
133+
const exprt &offset,
117134
const exprt &max_bytes,
118135
const namespacet &ns,
119136
bool unpack_byte_array)
@@ -141,6 +158,7 @@ static exprt unpack_rec(
141158
array_type.size(),
142159
*element_width,
143160
little_endian,
161+
offset,
144162
max_bytes,
145163
ns,
146164
array);
@@ -161,6 +179,7 @@ static exprt unpack_rec(
161179
vector_type.size(),
162180
*element_width,
163181
little_endian,
182+
offset,
164183
max_bytes,
165184
ns,
166185
array);
@@ -170,6 +189,8 @@ static exprt unpack_rec(
170189
const struct_typet &struct_type=to_struct_type(ns.follow(src.type()));
171190
const struct_typet::componentst &components=struct_type.components();
172191

192+
mp_integer member_offset_bits = 0;
193+
173194
for(const auto &comp : components)
174195
{
175196
auto element_width = pointer_offset_bits(comp.type(), ns);
@@ -182,11 +203,38 @@ static exprt unpack_rec(
182203
throw non_byte_alignedt(struct_type, comp, *element_width);
183204
}
184205

206+
exprt new_offset = nil_exprt();
207+
auto new_offset_int = numeric_cast<mp_integer>(offset);
208+
exprt new_max_bytes = nil_exprt();
209+
auto new_max_bytes_int = numeric_cast<mp_integer>(max_bytes);
210+
211+
if(new_offset_int.has_value())
212+
{
213+
*new_offset_int -= member_offset_bits / 8;
214+
if(*new_offset_int >= 0)
215+
new_offset = from_integer(*new_offset_int, offset.type());
216+
}
217+
218+
if(new_max_bytes_int.has_value())
219+
{
220+
*new_max_bytes_int -= member_offset_bits / 8;
221+
if(*new_max_bytes_int >= 0)
222+
new_max_bytes = from_integer(*new_max_bytes_int, max_bytes.type());
223+
else
224+
break;
225+
}
226+
185227
member_exprt member(src, comp.get_name(), comp.type());
186-
exprt sub=unpack_rec(member, little_endian, max_bytes, ns, true);
228+
if(src.id() == ID_struct)
229+
simplify(member, ns);
230+
231+
exprt sub =
232+
unpack_rec(member, little_endian, new_offset, new_max_bytes, ns, true);
187233

188234
for(const auto& op : sub.operands())
189235
array.copy_to_operands(op);
236+
237+
member_offset_bits += *element_width;
190238
}
191239
}
192240
else if(src.type().id()!=ID_empty)
@@ -294,9 +342,12 @@ exprt lower_byte_extract(const byte_extract_exprt &src, const namespacet &ns)
294342
typecast_exprt(src.offset(), upper_bound.type())),
295343
ns);
296344

345+
exprt lb = src.offset();
346+
if(!lb.is_constant())
347+
lb.make_nil();
348+
297349
byte_extract_exprt unpacked(src);
298-
unpacked.op()=
299-
unpack_rec(src.op(), little_endian, upper_bound, ns);
350+
unpacked.op() = unpack_rec(src.op(), little_endian, lb, upper_bound, ns);
300351

301352
if(src.type().id()==ID_array)
302353
{

0 commit comments

Comments
 (0)