@@ -18,8 +18,12 @@ Author: Daniel Kroening, kroening@kroening.com
18
18
#include < util/pointer_expr.h>
19
19
#include < util/pointer_offset_size.h>
20
20
#include < util/pointer_predicates.h>
21
+ #include < util/replace_expr.h>
21
22
#include < util/simplify_expr.h>
22
23
24
+ #include < solvers/prop/bdd_expr.h>
25
+ #include < solvers/prop/literal_expr.h>
26
+
23
27
// / Map bytes according to the configured endianness. The key difference to
24
28
// / endianness_mapt is that bv_endianness_mapt is aware of the bit-level
25
29
// / 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)
911
915
return encode (a, type);
912
916
}
913
917
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
916
920
{
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)
918
931
{
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;
923
933
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)
925
942
{
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
+ }
927
952
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
+ }
929
958
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);
933
961
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);
935
965
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
+ }
938
968
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 ());
941
974
942
- if (!is_dynamic)
943
- l2=!l2 ;
975
+ const auto &objects = pointer_logic. objects ;
976
+ std:: size_t number = 0 ;
944
977
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)
951
981
{
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 ;
955
986
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)
957
999
{
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
+ }
959
1009
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
+ }
962
1012
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);
964
1019
965
- if (!size_expr. has_value ())
966
- continue ;
1020
+ result. emplace (size_entry. first , bdd_converter. as_expr (bdd));
1021
+ }
967
1022
968
- const exprt object_size = typecast_exprt::conditional_cast (
969
- size_expr. value (), postponed_object_size-> type ());
1023
+ return result;
1024
+ }
970
1025
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 ();
974
1030
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;
976
1035
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;
978
1038
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);
982
1046
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)
985
1053
{
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]});
989
1056
}
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 ())
991
1077
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 ;
992
1109
#define COMPACT_OBJECT_SIZE_EQ
993
1110
#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);
995
1112
996
- prop.l_set_to_true (prop.limplies (l1, l2));
1113
+ prop.l_set_to_true (prop.limplies (l1, l2));
997
1114
#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
+ }
1003
1120
#endif
1121
+ }
1004
1122
}
1123
+ else
1124
+ UNREACHABLE;
1005
1125
}
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);
1020
1126
1021
1127
// Clear the list to avoid re-doing in case of incremental usage.
1022
1128
postponed_list.clear ();
0 commit comments