@@ -264,47 +264,81 @@ exprt flatten_byte_update(
264
264
else // sub_size!=1
265
265
{
266
266
exprt result=src.op0 ();
267
- unsignedbv_typet byte_type (8 );
268
267
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)
270
282
{
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
+
271
289
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
+ {
275
293
new_value=src.op2 ();
294
+ stored_value_offset=zero_offset;
295
+ }
276
296
else
277
297
{
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
+
278
308
byte_extract_exprt byte_extract_expr (
279
309
src.id ()==ID_byte_update_little_endian?ID_byte_extract_little_endian:
280
310
src.id ()==ID_byte_update_big_endian?ID_byte_extract_big_endian:
281
311
throw " unexpected src.id() in flatten_byte_update" ,
282
- byte_type );
312
+ element_size < sub_size ? src. op2 (). type () : subtype );
283
313
284
314
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;
289
316
290
- plus_exprt store_offset (src.op1 (),i_expr);
317
+ new_value=flatten_byte_extract (byte_extract_expr,ns);
318
+ }
291
319
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;
296
330
297
331
byte_update_exprt byte_update_expr (src.id (),
298
- index_expr ,
299
- mod_offset ,
332
+ old_cell_value ,
333
+ overwrite_offset ,
300
334
new_value);
301
335
302
- // Call recurisvely , the array is gone!
336
+ // Call recursively , the array is gone!
303
337
exprt flattened_byte_update_expr=
304
338
flatten_byte_update (byte_update_expr, ns);
305
-
339
+
306
340
with_exprt with_expr (
307
- result, div_offset , flattened_byte_update_expr);
341
+ result, cell_index , flattened_byte_update_expr);
308
342
309
343
result=with_expr;
310
344
}
@@ -334,18 +368,8 @@ exprt flatten_byte_update(
334
368
335
369
// build mask
336
370
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));
339
372
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
-
349
373
// zero-extend the value, but only if needed
350
374
exprt value_extended;
351
375
@@ -356,10 +380,23 @@ exprt flatten_byte_update(
356
380
else
357
381
value_extended=src.op2 ();
358
382
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
363
400
bitor_exprt bitor_expr (bitand_expr, value_shifted);
364
401
365
402
return bitor_expr;
0 commit comments