@@ -18,8 +18,12 @@ Author: Daniel Kroening, kroening@kroening.com
1818#include < util/pointer_expr.h>
1919#include < util/pointer_offset_size.h>
2020#include < util/pointer_predicates.h>
21+ #include < util/replace_expr.h>
2122#include < util/simplify_expr.h>
2223
24+ #include < solvers/prop/bdd_expr.h>
25+ #include < solvers/prop/literal_expr.h>
26+
2327// / Map bytes according to the configured endianness. The key difference to
2428// / endianness_mapt is that bv_endianness_mapt is aware of the bit-level
2529// / encoding of types, which need not co-incide with the bit layout at
@@ -911,112 +915,214 @@ bvt bv_pointerst::add_addr(const exprt &expr)
911915 return encode (a, type);
912916}
913917
914- void bv_pointerst::do_postponed (
915- const postponedt &postponed)
918+ std::pair<exprt, exprt> bv_pointerst::prepare_postponed_is_dynamic_object (
919+ std::vector<symbol_exprt> &placeholders) const
916920{
917- if (postponed.expr .id () == ID_is_dynamic_object)
921+ PRECONDITION (placeholders.empty ());
922+
923+ const auto &objects = pointer_logic.objects ;
924+ std::size_t number = 0 ;
925+
926+ exprt::operandst dynamic_objects_ops, not_dynamic_objects_ops;
927+ dynamic_objects_ops.reserve (objects.size ());
928+ not_dynamic_objects_ops.reserve (objects.size ());
929+
930+ for (auto it = objects.cbegin (); it != objects.cend (); ++it, ++number)
918931 {
919- const auto &type =
920- to_pointer_type (to_unary_expr (postponed.expr ).op ().type ());
921- const auto &objects = pointer_logic.objects ;
922- std::size_t number=0 ;
932+ const exprt &expr = *it;
923933
924- for (auto it = objects.cbegin (); it != objects.cend (); ++it, ++number)
934+ // only compare object part
935+ pointer_typet pt = pointer_type (expr.type ());
936+ bvt bv = object_literals (encode (number, pt), pt);
937+
938+ exprt::operandst conjuncts;
939+ conjuncts.reserve (bv.size ());
940+ placeholders.reserve (bv.size ());
941+ for (std::size_t i = 0 ; i < bv.size (); ++i)
925942 {
926- const exprt &expr=*it;
943+ if (placeholders.size () <= i)
944+ placeholders.push_back (symbol_exprt{std::to_string (i), bool_typet{}});
945+
946+ POSTCONDITION (bv[i].is_constant ());
947+ if (bv[i].is_true ())
948+ conjuncts.emplace_back (placeholders[i]);
949+ else
950+ conjuncts.emplace_back (not_exprt{placeholders[i]});
951+ }
927952
928- bool is_dynamic=pointer_logic.is_dynamic_object (expr);
953+ if (pointer_logic.is_dynamic_object (expr))
954+ dynamic_objects_ops.push_back (conjunction (conjuncts));
955+ else
956+ not_dynamic_objects_ops.push_back (conjunction (conjuncts));
957+ }
929958
930- // only compare object part
931- pointer_typet pt = pointer_type (expr.type ());
932- bvt bv = object_literals (encode (number, pt), type);
959+ exprt dynamic_objects = disjunction (dynamic_objects_ops);
960+ exprt not_dynamic_objects = disjunction (not_dynamic_objects_ops);
933961
934- bvt saved_bv = object_literals (postponed.op , type);
962+ bdd_exprt bdd_converter;
963+ bddt dyn_bdd = bdd_converter.from_expr (dynamic_objects);
964+ bddt not_dyn_bdd = bdd_converter.from_expr (not_dynamic_objects);
935965
936- POSTCONDITION (bv. size ()==saved_bv. size ()) ;
937- PRECONDITION (postponed. bv . size ()== 1 );
966+ return {bdd_converter. as_expr (dyn_bdd), bdd_converter. as_expr (not_dyn_bdd)} ;
967+ }
938968
939- literalt l1=bv_utils.equal (bv, saved_bv);
940- literalt l2=postponed.bv .front ();
969+ std::unordered_map<exprt, exprt, irep_hash>
970+ bv_pointerst::prepare_postponed_object_size (
971+ std::vector<symbol_exprt> &placeholders) const
972+ {
973+ PRECONDITION (placeholders.empty ());
941974
942- if (!is_dynamic)
943- l2=!l2 ;
975+ const auto &objects = pointer_logic. objects ;
976+ std:: size_t number = 0 ;
944977
945- prop.l_set_to_true (prop.limplies (l1, l2));
946- }
947- }
948- else if (
949- const auto postponed_object_size =
950- expr_try_dynamic_cast<object_size_exprt>(postponed.expr ))
978+ std::unordered_map<exprt, exprt::operandst, irep_hash> per_size_object_ops;
979+
980+ for (auto it = objects.cbegin (); it != objects.cend (); ++it, ++number)
951981 {
952- const auto &type = to_pointer_type (postponed_object_size->pointer ().type ());
953- const auto &objects = pointer_logic.objects ;
954- std::size_t number=0 ;
982+ const exprt &expr = *it;
983+
984+ if (expr.id () != ID_symbol && expr.id () != ID_string_constant)
985+ continue ;
955986
956- for (auto it = objects.cbegin (); it != objects.cend (); ++it, ++number)
987+ const auto size_expr = size_of_expr (expr.type (), ns);
988+ if (!size_expr.has_value ())
989+ continue ;
990+
991+ // only compare object part
992+ pointer_typet pt = pointer_type (expr.type ());
993+ bvt bv = object_literals (encode (number, pt), pt);
994+
995+ exprt::operandst conjuncts;
996+ conjuncts.reserve (bv.size ());
997+ placeholders.reserve (bv.size ());
998+ for (std::size_t i = 0 ; i < bv.size (); ++i)
957999 {
958- const exprt &expr=*it;
1000+ if (placeholders.size () <= i)
1001+ placeholders.push_back (symbol_exprt{std::to_string (i), bool_typet{}});
1002+
1003+ POSTCONDITION (bv[i].is_constant ());
1004+ if (bv[i].is_true ())
1005+ conjuncts.emplace_back (placeholders[i]);
1006+ else
1007+ conjuncts.emplace_back (not_exprt{placeholders[i]});
1008+ }
9591009
960- if (expr. id () != ID_symbol && expr. id () != ID_string_constant)
961- continue ;
1010+ per_size_object_ops[size_expr. value ()]. push_back ( conjunction (conjuncts));
1011+ }
9621012
963- const auto size_expr = size_of_expr (expr.type (), ns);
1013+ std::unordered_map<exprt, exprt, irep_hash> result;
1014+ for (const auto &size_entry : per_size_object_ops)
1015+ {
1016+ exprt all_objects_this_size = disjunction (size_entry.second );
1017+ bdd_exprt bdd_converter;
1018+ bddt bdd = bdd_converter.from_expr (all_objects_this_size);
9641019
965- if (!size_expr. has_value ())
966- continue ;
1020+ result. emplace (size_entry. first , bdd_converter. as_expr (bdd));
1021+ }
9671022
968- const exprt object_size = typecast_exprt::conditional_cast (
969- size_expr. value (), postponed_object_size-> type ());
1023+ return result;
1024+ }
9701025
971- // only compare object part
972- pointer_typet pt = pointer_type (expr.type ());
973- bvt bv = object_literals (encode (number, pt), type);
1026+ void bv_pointerst::finish_eager_conversion ()
1027+ {
1028+ // post-processing arrays may yield further objects, do this first
1029+ SUB::finish_eager_conversion ();
9741030
975- bvt saved_bv = object_literals (postponed.op , type);
1031+ // it would seem nicer to use `optionalt` here, but GCC >= 12 produces
1032+ // spurious warnings about accessing uninitialized objects
1033+ std::pair<exprt, exprt> is_dynamic_expr = {nil_exprt{}, nil_exprt{}};
1034+ std::vector<symbol_exprt> is_dynamic_placeholders;
9761035
977- bvt size_bv = convert_bv (object_size);
1036+ std::unordered_map<exprt, exprt, irep_hash> object_sizes;
1037+ std::vector<symbol_exprt> object_size_placeholders;
9781038
979- POSTCONDITION (bv.size ()==saved_bv.size ());
980- PRECONDITION (postponed.bv .size ()>=1 );
981- PRECONDITION (size_bv.size () == postponed.bv .size ());
1039+ for (const postponedt &postponed : postponed_list)
1040+ {
1041+ if (postponed.expr .id () == ID_is_dynamic_object)
1042+ {
1043+ if (is_dynamic_expr.first .is_nil ())
1044+ is_dynamic_expr =
1045+ prepare_postponed_is_dynamic_object (is_dynamic_placeholders);
9821046
983- literalt l1=bv_utils.equal (bv, saved_bv);
984- if (l1.is_true ())
1047+ const auto &type =
1048+ to_pointer_type (to_unary_expr (postponed.expr ).op ().type ());
1049+ bvt saved_bv = object_literals (postponed.op , type);
1050+ POSTCONDITION (saved_bv.size () == is_dynamic_placeholders.size ());
1051+ replace_mapt replacements;
1052+ for (std::size_t i = 0 ; i < saved_bv.size (); ++i)
9851053 {
986- for (std::size_t i = 0 ; i < postponed.bv .size (); ++i)
987- prop.set_equal (postponed.bv [i], size_bv[i]);
988- break ;
1054+ replacements.emplace (
1055+ is_dynamic_placeholders[i], literal_exprt{saved_bv[i]});
9891056 }
990- else if (l1.is_false ())
1057+ exprt is_dyn = is_dynamic_expr.first ;
1058+ replace_expr (replacements, is_dyn);
1059+ exprt is_not_dyn = is_dynamic_expr.second ;
1060+ replace_expr (replacements, is_not_dyn);
1061+
1062+ PRECONDITION (postponed.bv .size () == 1 );
1063+ prop.l_set_to_true (
1064+ prop.limplies (convert_bv (is_dyn)[0 ], postponed.bv .front ()));
1065+ prop.l_set_to_true (
1066+ prop.limplies (convert_bv (is_not_dyn)[0 ], !postponed.bv .front ()));
1067+ }
1068+ else if (
1069+ const auto postponed_object_size =
1070+ expr_try_dynamic_cast<object_size_exprt>(postponed.expr ))
1071+ {
1072+ if (object_sizes.empty ())
1073+ object_sizes = prepare_postponed_object_size (object_size_placeholders);
1074+
1075+ // we might not have any usable objects
1076+ if (object_size_placeholders.empty ())
9911077 continue ;
1078+
1079+ const auto &type =
1080+ to_pointer_type (postponed_object_size->pointer ().type ());
1081+ bvt saved_bv = object_literals (postponed.op , type);
1082+ POSTCONDITION (saved_bv.size () == object_size_placeholders.size ());
1083+ replace_mapt replacements;
1084+ for (std::size_t i = 0 ; i < saved_bv.size (); ++i)
1085+ {
1086+ replacements.emplace (
1087+ object_size_placeholders[i], literal_exprt{saved_bv[i]});
1088+ }
1089+
1090+ for (const auto &object_size_entry : object_sizes)
1091+ {
1092+ const exprt object_size = typecast_exprt::conditional_cast (
1093+ object_size_entry.first , postponed_object_size->type ());
1094+ bvt size_bv = convert_bv (object_size);
1095+ POSTCONDITION (size_bv.size () == postponed.bv .size ());
1096+
1097+ exprt all_objects_this_size = object_size_entry.second ;
1098+ replace_expr (replacements, all_objects_this_size);
1099+
1100+ literalt l1 = convert_bv (all_objects_this_size)[0 ];
1101+ if (l1.is_true ())
1102+ {
1103+ for (std::size_t i = 0 ; i < postponed.bv .size (); ++i)
1104+ prop.set_equal (postponed.bv [i], size_bv[i]);
1105+ break ;
1106+ }
1107+ else if (l1.is_false ())
1108+ continue ;
9921109#define COMPACT_OBJECT_SIZE_EQ
9931110#ifndef COMPACT_OBJECT_SIZE_EQ
994- literalt l2= bv_utils.equal (postponed.bv , size_bv);
1111+ literalt l2 = bv_utils.equal (postponed.bv , size_bv);
9951112
996- prop.l_set_to_true (prop.limplies (l1, l2));
1113+ prop.l_set_to_true (prop.limplies (l1, l2));
9971114#else
998- for (std::size_t i = 0 ; i < postponed.bv .size (); ++i)
999- {
1000- prop.lcnf ({!l1, !postponed.bv [i], size_bv[i]});
1001- prop.lcnf ({!l1, postponed.bv [i], !size_bv[i]});
1002- }
1115+ for (std::size_t i = 0 ; i < postponed.bv .size (); ++i)
1116+ {
1117+ prop.lcnf ({!l1, !postponed.bv [i], size_bv[i]});
1118+ prop.lcnf ({!l1, postponed.bv [i], !size_bv[i]});
1119+ }
10031120#endif
1121+ }
10041122 }
1123+ else
1124+ UNREACHABLE;
10051125 }
1006- else
1007- UNREACHABLE;
1008- }
1009-
1010- void bv_pointerst::finish_eager_conversion ()
1011- {
1012- // post-processing arrays may yield further objects, do this first
1013- SUB::finish_eager_conversion ();
1014-
1015- for (postponed_listt::const_iterator
1016- it=postponed_list.begin ();
1017- it!=postponed_list.end ();
1018- it++)
1019- do_postponed (*it);
10201126
10211127 // Clear the list to avoid re-doing in case of incremental usage.
10221128 postponed_list.clear ();
0 commit comments