@@ -15,13 +15,15 @@ Author: Peter Schrammel
15
15
#include < util/bitvector_expr.h>
16
16
#include < util/byte_operators.h>
17
17
#include < util/c_types.h>
18
+ #include < util/config.h>
18
19
#include < util/format_expr.h>
19
20
#include < util/invariant.h>
20
21
#include < util/namespace.h>
21
22
#include < util/pointer_offset_size.h>
22
23
#include < util/ssa_expr.h>
23
24
#include < util/std_expr.h>
24
25
26
+ #include < solvers/flattening/boolbv_width.h>
25
27
26
28
// TODO: change DEBUG_SM to DEBUG_SHADOW_MEMORY (it also appears in other files)
27
29
@@ -428,119 +430,120 @@ exprt compute_or_over_cells(
428
430
return or_values (values, field_type);
429
431
}
430
432
431
- // TODO: doxygen?
432
- static void
433
- max_element (const exprt &element, const typet &field_type, exprt &max)
433
+ // / Create an expression comparing the element at `expr_iterator` with the
434
+ // / following elements of the collection (or `nil_exprt`if none) and return a
435
+ // / pair `(condition, element)` such that if the condition is `true`, then the
436
+ // / element is the max of the collection in the interval denoted by
437
+ // / `expr_iterator` and `end`.
438
+ // / \param expr_iterator the iterator pointing at the element to compare to.
439
+ // / \param end the end of collection iterator.
440
+ // / \return A pair (cond, elem) containing the condition and the max element.
441
+ std::pair<exprt, exprt> compare_to_collection (
442
+ const std::vector<exprt>::const_iterator &expr_iterator,
443
+ const std::vector<exprt>::const_iterator &end)
434
444
{
435
- exprt value = typecast_exprt::conditional_cast (element, field_type);
436
- if (max.is_nil ())
445
+ // We need at least an element in the collection
446
+ INVARIANT (expr_iterator != end, " Cannot compute max of an empty collection" );
447
+ const exprt ¤t_expr = *expr_iterator;
448
+
449
+ // Iterator for the other elements in the collection in the interval denoted
450
+ // by `expr_iterator` and `end`.
451
+ std::vector<exprt>::const_iterator expr_to_compare_to =
452
+ std::next (expr_iterator);
453
+ if (expr_to_compare_to == end)
437
454
{
438
- max = value ;
455
+ return {nil_exprt{}, current_expr} ;
439
456
}
440
- else
457
+
458
+ std::vector<exprt> comparisons;
459
+ for (; expr_to_compare_to != end; ++expr_to_compare_to)
441
460
{
442
- max = if_exprt (binary_predicate_exprt (value, ID_gt, max), value, max);
461
+ // Compare the current element with the n-th following it
462
+ comparisons.emplace_back (
463
+ binary_predicate_exprt (current_expr, ID_gt, *expr_to_compare_to));
443
464
}
465
+
466
+ return {and_exprt (comparisons), current_expr};
444
467
}
445
468
446
- // TODO: doxygen?
447
- static void max_over_bytes (
448
- const exprt &value,
449
- const typet &type,
450
- const typet &field_type,
451
- exprt &max)
469
+ // / Combine each (condition, value) element in the input collection into a
470
+ // / if-then-else expression such as
471
+ // / (cond_1 ? val_1 : (cond_2 ? val_2 : ... : val_n))
472
+ // / \param conditions_and_values collection containing codnition-value pairs
473
+ // / \return the combined max expression
474
+ static exprt combine_condition_and_max_values (
475
+ const std::vector<std::pair<exprt, exprt>> &conditions_and_values)
452
476
{
453
- const size_t size = to_bitvector_type (type).get_width () / 8 ;
454
- max_element (value, field_type, max);
455
- for (size_t i = 1 ; i < size; ++i)
477
+ // We need at least one element
478
+ INVARIANT (
479
+ conditions_and_values.size () > 0 ,
480
+ " Cannot compute max of an empty collection" );
481
+
482
+ // We use reverse-iterator, so the last element is the one in the last else
483
+ // case.
484
+ auto reverse_ite = conditions_and_values.rbegin ();
485
+
486
+ // The last element must have `nil_exprt` as condition
487
+ INVARIANT (
488
+ reverse_ite->first == nil_exprt{},
489
+ " Last element of condition-value list must have nil_exprt condition." );
490
+
491
+ exprt res = std::move (reverse_ite->second );
492
+
493
+ for (++reverse_ite; reverse_ite != conditions_and_values.rend (); ++reverse_ite)
456
494
{
457
- max_element (
458
- lshr_exprt (value, from_integer (8 * i, size_type ())), field_type, max);
495
+ res = if_exprt (reverse_ite->first , reverse_ite->second , res);
459
496
}
497
+
498
+ return res;
460
499
}
461
500
462
- // TODO: doxygen?
463
- static void max_elements (
464
- exprt element,
465
- const typet &field_type,
466
- const namespacet &ns,
467
- const messaget &log,
468
- const bool is_union,
469
- exprt &max)
501
+ // / Create an expression encoding the max operation over the collection `values`
502
+ // / \param values an `exprt` that encodes the max of `values`
503
+ // / \return an `exprt` encoding the max operation over the collection `values`
504
+ static exprt create_max_expr (const std::vector<exprt> &values)
470
505
{
471
- element = conditional_cast_floatbv_to_unsignedbv (element);
472
- if (element.type ().id () == ID_unsignedbv || element.type ().id () == ID_signedbv)
473
- {
474
- if (is_union)
475
- {
476
- max_over_bytes (element, element.type (), field_type, max);
477
- }
478
- else
479
- {
480
- max_element (element, field_type, max);
481
- }
482
- }
483
- else
506
+ std::vector<std::pair<exprt, exprt>> rows;
507
+ rows.reserve (values.size ());
508
+ for (auto byte_it = values.begin (); byte_it != values.end (); ++byte_it)
484
509
{
485
- exprt value =
486
- compute_max_over_cells ( element, field_type, ns, log , is_union);
487
- max_element (value, field_type, max );
510
+ // Create a pair condition-element where the condition is the comparison of
511
+ // the element with all the ones contained in the rest of the collection.
512
+ rows. emplace_back ( compare_to_collection (byte_it, values. end ()) );
488
513
}
514
+
515
+ return combine_condition_and_max_values (rows);
489
516
}
490
517
491
518
exprt compute_max_over_cells (
492
519
const exprt &expr,
493
520
const typet &field_type,
494
- const namespacet &ns,
495
- const messaget &log,
496
- const bool is_union)
521
+ const namespacet &ns)
497
522
{
498
- const typet type = ns.follow (expr.type ());
523
+ // Compute the bit-width of the type of `expr`.
524
+ std::size_t size = boolbv_widtht{ns}(expr.type ());
499
525
500
- if (type.id () == ID_struct || type.id () == ID_union)
526
+ // Compute how many bytes are in `expr`
527
+ std::size_t byte_count = size / config.ansi_c .char_width ;
528
+
529
+ // Extract each byte of `expr` by using byte_extract.
530
+ std::vector<exprt> extracted_bytes;
531
+ extracted_bytes.reserve (byte_count);
532
+ for (std::size_t i = 0 ; i < byte_count; ++i)
501
533
{
502
- exprt max = nil_exprt ();
503
- for (const auto &component : to_struct_union_type (type).components ())
504
- {
505
- if (component.get_is_padding ())
506
- {
507
- continue ;
508
- }
509
- max_elements (
510
- member_exprt (expr, component), field_type, ns, log , is_union, max);
511
- }
512
- return max;
534
+ extracted_bytes.emplace_back (make_byte_extract (
535
+ expr, from_integer (i, unsigned_long_int_type ()), field_type));
513
536
}
514
- else if (type.id () == ID_array)
515
- {
516
- const array_typet &array_type = to_array_type (type);
517
- if (array_type.size ().is_constant ())
518
- {
519
- exprt max = nil_exprt ();
520
- const mp_integer size =
521
- numeric_cast_v<mp_integer>(to_constant_expr (array_type.size ()));
522
- for (mp_integer index = 0 ; index < size; ++index )
523
- {
524
- max_elements (
525
- index_exprt (expr, from_integer (index , index_type ())),
526
- field_type,
527
- ns,
528
- log ,
529
- is_union,
530
- max);
531
- }
532
- return max;
533
- }
534
- else
535
- {
536
- log .warning ()
537
- << " Shadow memory: cannot compute max over variable-size array "
538
- << format (expr) << messaget::eom;
539
- }
540
- }
541
- // TODO: This is incorrect when accessing non-0 offsets of scalars.
542
- return typecast_exprt::conditional_cast (
543
- conditional_cast_floatbv_to_unsignedbv (expr), field_type);
537
+
538
+ // Compute the max of the bytes extracted from `expr`.
539
+ exprt max_expr = create_max_expr (extracted_bytes);
540
+
541
+ INVARIANT (
542
+ max_expr.type () == field_type,
543
+ " Aggregated max value type must be the same as shadow memory field's "
544
+ " type." );
545
+
546
+ return max_expr;
544
547
}
545
548
546
549
// TODO: doxygen?
@@ -819,10 +822,7 @@ std::vector<std::pair<exprt, exprt>> get_shadow_dereference_candidates(
819
822
else
820
823
{
821
824
// Value is of other (bitvector) type, so aggregate with max
822
- value = typecast_exprt::conditional_cast (
823
- compute_max_over_cells (
824
- shadow_dereference.value , field_type, ns, log , is_union),
825
- lhs_type);
825
+ value = compute_max_over_cells (shadow_dereference.value , field_type, ns);
826
826
}
827
827
828
828
const exprt base_cond = get_matched_base_cond (
0 commit comments