@@ -15,13 +15,15 @@ Author: Peter Schrammel
1515#include < util/bitvector_expr.h>
1616#include < util/byte_operators.h>
1717#include < util/c_types.h>
18+ #include < util/config.h>
1819#include < util/format_expr.h>
1920#include < util/invariant.h>
2021#include < util/namespace.h>
2122#include < util/pointer_offset_size.h>
2223#include < util/ssa_expr.h>
2324#include < util/std_expr.h>
2425
26+ #include < solvers/flattening/boolbv_width.h>
2527
2628// TODO: change DEBUG_SM to DEBUG_SHADOW_MEMORY (it also appears in other files)
2729
@@ -428,119 +430,120 @@ exprt compute_or_over_cells(
428430 return or_values (values, field_type);
429431}
430432
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)
434444{
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)
437454 {
438- max = value ;
455+ return {nil_exprt{}, current_expr} ;
439456 }
440- else
457+
458+ std::vector<exprt> comparisons;
459+ for (; expr_to_compare_to != end; ++expr_to_compare_to)
441460 {
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));
443464 }
465+
466+ return {and_exprt (comparisons), current_expr};
444467}
445468
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)
452476{
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)
456494 {
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);
459496 }
497+
498+ return res;
460499}
461500
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)
470505{
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)
484509 {
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 ()) );
488513 }
514+
515+ return combine_condition_and_max_values (rows);
489516}
490517
491518exprt compute_max_over_cells (
492519 const exprt &expr,
493520 const typet &field_type,
494- const namespacet &ns,
495- const messaget &log,
496- const bool is_union)
521+ const namespacet &ns)
497522{
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 ());
499525
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)
501533 {
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));
513536 }
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;
544547}
545548
546549// TODO: doxygen?
@@ -819,10 +822,7 @@ std::vector<std::pair<exprt, exprt>> get_shadow_dereference_candidates(
819822 else
820823 {
821824 // 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);
826826 }
827827
828828 const exprt base_cond = get_matched_base_cond (
0 commit comments