|
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