Skip to content

Commit fa2666b

Browse files
committed
Implement byte update against non-char arrays with linear cost.
However the formulae it produces are still quite large. Need to figure out where all the expensive operations are.
1 parent fd1bbd1 commit fa2666b

File tree

1 file changed

+72
-35
lines changed

1 file changed

+72
-35
lines changed

src/solvers/flattening/flatten_byte_operators.cpp

Lines changed: 72 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -264,47 +264,81 @@ exprt flatten_byte_update(
264264
else // sub_size!=1
265265
{
266266
exprt result=src.op0();
267-
unsignedbv_typet byte_type(8);
268267

269-
for(mp_integer i=0; i<element_size; ++i)
268+
// Number of potentially affected array cells:
269+
mp_integer num_elements=
270+
element_size/sub_size+((element_size%sub_size==0)?1:2);
271+
272+
const auto& offset_type=ns.follow(src.op1().type());
273+
exprt zero_offset=from_integer(0,offset_type);
274+
275+
exprt sub_size_expr=from_integer(sub_size,offset_type);
276+
exprt element_size_expr=from_integer(element_size,offset_type);
277+
278+
// First potentially affected cell:
279+
div_exprt first_cell(src.op1(),sub_size_expr);
280+
281+
for(mp_integer i=0; i<num_elements; ++i)
270282
{
283+
plus_exprt cell_index(first_cell,from_integer(i,offset_type));
284+
mult_exprt cell_offset(cell_index,sub_size_expr);
285+
index_exprt old_cell_value(src.op0(),cell_index,subtype);
286+
bool is_first_cell=i==0;
287+
bool is_last_cell=i==num_elements-1;
288+
271289
exprt new_value;
272-
exprt i_expr=from_integer(i, ns.follow(src.op1().type()));
273-
274-
if(element_size==1)
290+
exprt stored_value_offset;
291+
if(element_size <= sub_size)
292+
{
275293
new_value=src.op2();
294+
stored_value_offset=zero_offset;
295+
}
276296
else
277297
{
298+
// Offset to retrieve from the stored value: make sure not to
299+
// ask for anything out of range; in the first- or last-cell cases
300+
// we will adjust the offset in the byte_update call below.
301+
if(is_first_cell)
302+
stored_value_offset=zero_offset;
303+
else if(is_last_cell)
304+
stored_value_offset=from_integer(element_size-sub_size, offset_type);
305+
else
306+
stored_value_offset=minus_exprt(cell_offset,src.op1());
307+
278308
byte_extract_exprt byte_extract_expr(
279309
src.id()==ID_byte_update_little_endian?ID_byte_extract_little_endian:
280310
src.id()==ID_byte_update_big_endian?ID_byte_extract_big_endian:
281311
throw "unexpected src.id() in flatten_byte_update",
282-
byte_type);
312+
element_size < sub_size ? src.op2().type() : subtype);
283313

284314
byte_extract_expr.op()=src.op2();
285-
byte_extract_expr.offset()=i_expr;
286-
287-
new_value=byte_extract_expr;
288-
}
315+
byte_extract_expr.offset()=stored_value_offset;
289316

290-
plus_exprt store_offset(src.op1(),i_expr);
317+
new_value=flatten_byte_extract(byte_extract_expr,ns);
318+
}
291319

292-
div_exprt div_offset(store_offset, from_integer(sub_size, store_offset.type()));
293-
mod_exprt mod_offset(store_offset, from_integer(sub_size, store_offset.type()));
294-
295-
index_exprt index_expr(result, div_offset, array_type.subtype());
320+
// Where does the value we just extracted align in this cell?
321+
// This value might be negative, indicating only the most-significant bytes
322+
// should be written, to the least-significant bytes of the target array cell.
323+
exprt overwrite_offset;
324+
if(is_first_cell)
325+
overwrite_offset=mod_exprt(src.op1(),sub_size_expr);
326+
else if(is_last_cell)
327+
overwrite_offset=minus_exprt(stored_value_offset,minus_exprt(cell_offset,src.op1()));
328+
else
329+
overwrite_offset=zero_offset;
296330

297331
byte_update_exprt byte_update_expr(src.id(),
298-
index_expr,
299-
mod_offset,
332+
old_cell_value,
333+
overwrite_offset,
300334
new_value);
301335

302-
// Call recurisvely, the array is gone!
336+
// Call recursively, the array is gone!
303337
exprt flattened_byte_update_expr=
304338
flatten_byte_update(byte_update_expr, ns);
305-
339+
306340
with_exprt with_expr(
307-
result, div_offset, flattened_byte_update_expr);
341+
result, cell_index, flattened_byte_update_expr);
308342

309343
result=with_expr;
310344
}
@@ -334,18 +368,8 @@ exprt flatten_byte_update(
334368

335369
// build mask
336370
exprt mask=
337-
bitnot_exprt(
338-
from_integer(power(2, element_size*8)-1, unsignedbv_typet(width)));
371+
from_integer(power(2, element_size*8)-1, unsignedbv_typet(width));
339372

340-
const typet &offset_type=ns.follow(src.op1().type());
341-
mult_exprt offset_times_eight(src.op1(), from_integer(8, offset_type));
342-
343-
// shift the mask
344-
shl_exprt shl_expr(mask, offset_times_eight);
345-
346-
// do the 'AND'
347-
bitand_exprt bitand_expr(src.op0(), mask);
348-
349373
// zero-extend the value, but only if needed
350374
exprt value_extended;
351375

@@ -356,10 +380,23 @@ exprt flatten_byte_update(
356380
else
357381
value_extended=src.op2();
358382

359-
// shift the value
360-
shl_exprt value_shifted(value_extended, offset_times_eight);
361-
362-
// do the 'OR'
383+
const typet &offset_type=ns.follow(src.op1().type());
384+
mult_exprt offset_times_eight(src.op1(), from_integer(8, offset_type));
385+
386+
binary_predicate_exprt offset_ge_zero(offset_times_eight,ID_ge,from_integer(0,offset_type));
387+
388+
// Shift the mask and value. Note either shift might discard some of the new value's bits.
389+
if_exprt mask_shifted(offset_ge_zero,
390+
shl_exprt(mask,offset_times_eight),
391+
lshr_exprt(mask,unary_minus_exprt(offset_times_eight)));
392+
if_exprt value_shifted(offset_ge_zero,
393+
shl_exprt(value_extended,offset_times_eight),
394+
lshr_exprt(value_extended,unary_minus_exprt(offset_times_eight)));
395+
396+
// original_bits &= ~mask
397+
bitand_exprt bitand_expr(src.op0(), bitnot_exprt(mask_shifted));
398+
399+
// original_bits |= newvalue
363400
bitor_exprt bitor_expr(bitand_expr, value_shifted);
364401

365402
return bitor_expr;

0 commit comments

Comments
 (0)