@@ -190,7 +190,8 @@ Function: flatten_byte_update
190
190
191
191
exprt flatten_byte_update (
192
192
const byte_update_exprt &src,
193
- const namespacet &ns)
193
+ const namespacet &ns,
194
+ bool negative_offset)
194
195
{
195
196
assert (src.operands ().size ()==3 );
196
197
@@ -265,44 +266,95 @@ exprt flatten_byte_update(
265
266
{
266
267
exprt result=src.op0 ();
267
268
268
- for (mp_integer i=0 ; i<element_size; ++i)
269
+ // Number of potentially affected array cells:
270
+ mp_integer num_elements=
271
+ element_size/sub_size+((element_size%sub_size==0 )?1 :2 );
272
+
273
+ const auto & offset_type=ns.follow (src.op1 ().type ());
274
+ exprt zero_offset=from_integer (0 , offset_type);
275
+
276
+ exprt sub_size_expr=from_integer (sub_size, offset_type);
277
+ exprt element_size_expr=from_integer (element_size, offset_type);
278
+
279
+ // First potentially affected cell:
280
+ div_exprt first_cell (src.op1 (), sub_size_expr);
281
+
282
+ for (mp_integer i=0 ; i<num_elements; ++i)
269
283
{
270
- exprt new_value;
284
+ plus_exprt cell_index (first_cell, from_integer (i, offset_type));
285
+ mult_exprt cell_offset (cell_index, sub_size_expr);
286
+ index_exprt old_cell_value (src.op0 (), cell_index, subtype);
287
+ bool is_first_cell=i==0 ;
288
+ bool is_last_cell=i==num_elements-1 ;
271
289
272
- if (element_size==1 )
290
+ exprt new_value;
291
+ exprt stored_value_offset;
292
+ if (element_size<=sub_size)
293
+ {
273
294
new_value=src.op2 ();
295
+ stored_value_offset=zero_offset;
296
+ }
274
297
else
275
298
{
276
- exprt i_expr=from_integer (i, ns.follow (src.op1 ().type ()));
277
-
299
+ // Offset to retrieve from the stored value: make sure not to
300
+ // ask for anything out of range; in the first- or last-cell cases
301
+ // we will adjust the offset in the byte_update call below.
302
+ if (is_first_cell)
303
+ stored_value_offset=zero_offset;
304
+ else if (is_last_cell)
305
+ stored_value_offset=
306
+ from_integer (element_size-sub_size, offset_type);
307
+ else
308
+ stored_value_offset=minus_exprt (cell_offset, src.op1 ());
309
+
310
+ auto extract_opcode=
311
+ src.id ()==ID_byte_update_little_endian ?
312
+ ID_byte_extract_little_endian :
313
+ src.id ()==ID_byte_update_big_endian ?
314
+ ID_byte_extract_big_endian :
315
+ throw " unexpected src.id() in flatten_byte_update" ;
278
316
byte_extract_exprt byte_extract_expr (
279
- src.id ()==ID_byte_update_little_endian?ID_byte_extract_little_endian:
280
- src.id ()==ID_byte_update_big_endian?ID_byte_extract_big_endian:
281
- throw " unexpected src.id() in flatten_byte_update" ,
282
- array_type.subtype ());
317
+ extract_opcode,
318
+ element_size<sub_size ? src.op2 ().type () : subtype);
283
319
284
320
byte_extract_expr.op ()=src.op2 ();
285
- byte_extract_expr.offset ()=i_expr ;
321
+ byte_extract_expr.offset ()=stored_value_offset ;
286
322
287
- new_value=byte_extract_expr;
323
+ new_value=flatten_byte_extract ( byte_extract_expr, ns) ;
288
324
}
289
325
290
- div_exprt div_offset (src.op1 (), from_integer (sub_size, src.op1 ().type ()));
291
- mod_exprt mod_offset (src.op1 (), from_integer (sub_size, src.op1 ().type ()));
292
-
293
- index_exprt index_expr (src.op0 (), div_offset, array_type.subtype ());
326
+ // Where does the value we just extracted align in this cell?
327
+ // This value might be negative, indicating only the most-significant
328
+ // bytes should be written, to the least-significant bytes of the
329
+ // target array cell.
330
+ exprt overwrite_offset;
331
+ if (is_first_cell)
332
+ overwrite_offset=mod_exprt (src.op1 (), sub_size_expr);
333
+ else if (is_last_cell)
334
+ {
335
+ // This is intentionally negated; passing is_last_cell
336
+ // to flatten below leads to it being negated again later.
337
+ overwrite_offset=
338
+ minus_exprt (
339
+ minus_exprt (cell_offset, src.op1 ()),
340
+ stored_value_offset);
341
+ }
342
+ else
343
+ overwrite_offset=zero_offset;
294
344
295
- byte_update_exprt byte_update_expr (src.id (), array_type.subtype ());
296
- byte_update_expr.op ()=index_expr;
297
- byte_update_expr.offset ()=mod_offset;
298
- byte_update_expr.value ()=new_value;
345
+ byte_update_exprt byte_update_expr (
346
+ src.id (),
347
+ old_cell_value,
348
+ overwrite_offset,
349
+ new_value);
299
350
300
- // Call recurisvely, the array is gone!
351
+ // Call recursively, the array is gone!
352
+ // The last parameter indicates that the
301
353
exprt flattened_byte_update_expr=
302
- flatten_byte_update (byte_update_expr, ns);
354
+ flatten_byte_update (byte_update_expr, ns, is_last_cell );
303
355
304
356
with_exprt with_expr (
305
- result, div_offset , flattened_byte_update_expr);
357
+ result, cell_index , flattened_byte_update_expr);
306
358
307
359
result=with_expr;
308
360
}
@@ -332,17 +384,7 @@ exprt flatten_byte_update(
332
384
333
385
// build mask
334
386
exprt mask=
335
- bitnot_exprt (
336
- from_integer (power (2 , element_size*8 )-1 , unsignedbv_typet (width)));
337
-
338
- const typet &offset_type=ns.follow (src.op1 ().type ());
339
- mult_exprt offset_times_eight (src.op1 (), from_integer (8 , offset_type));
340
-
341
- // shift the mask
342
- shl_exprt shl_expr (mask, offset_times_eight);
343
-
344
- // do the 'AND'
345
- bitand_exprt bitand_expr (src.op0 (), mask);
387
+ from_integer (power (2 , element_size*8 )-1 , unsignedbv_typet (width));
346
388
347
389
// zero-extend the value, but only if needed
348
390
exprt value_extended;
@@ -354,10 +396,35 @@ exprt flatten_byte_update(
354
396
else
355
397
value_extended=src.op2 ();
356
398
357
- // shift the value
358
- shl_exprt value_shifted (value_extended, offset_times_eight);
399
+ const typet &offset_type=ns.follow (src.op1 ().type ());
400
+ mult_exprt offset_times_eight (src.op1 (), from_integer (8 , offset_type));
401
+
402
+ binary_predicate_exprt offset_ge_zero (
403
+ offset_times_eight,
404
+ ID_ge,
405
+ from_integer (0 , offset_type));
406
+
407
+ // Shift the mask and value.
408
+ // Note either shift might discard some of the new value's bits.
409
+ exprt mask_shifted;
410
+ exprt value_shifted;
411
+ if (negative_offset)
412
+ {
413
+ // In this case we shift right, to mask out higher addresses
414
+ // rather than left to mask out lower ones as usual.
415
+ mask_shifted=lshr_exprt (mask, offset_times_eight);
416
+ value_shifted=lshr_exprt (value_extended, offset_times_eight);
417
+ }
418
+ else
419
+ {
420
+ mask_shifted=shl_exprt (mask, offset_times_eight);
421
+ value_shifted=shl_exprt (value_extended, offset_times_eight);
422
+ }
423
+
424
+ // original_bits &= ~mask
425
+ bitand_exprt bitand_expr (src.op0 (), bitnot_exprt (mask_shifted));
359
426
360
- // do the 'OR'
427
+ // original_bits |= newvalue
361
428
bitor_exprt bitor_expr (bitand_expr, value_shifted);
362
429
363
430
return bitor_expr;
0 commit comments