11 namespace BV_ConstantPropagation
20 BooleanFunction And(
const std::vector<BooleanFunction::Value>& p0,
const std::vector<BooleanFunction::Value>& p1)
22 std::vector<BooleanFunction::Value> simplified;
23 simplified.reserve(p0.size());
24 for (
auto i = 0u; i < p0.size(); i++)
26 if ((p0[i] == 0) || (p1[i] == 0))
28 simplified.emplace_back(BooleanFunction::Value::ZERO);
30 else if ((p0[i] == 1) && (p1[i] == 1))
32 simplified.emplace_back(BooleanFunction::Value::ONE);
36 simplified.emplace_back(BooleanFunction::Value::X);
49 BooleanFunction Or(
const std::vector<BooleanFunction::Value>& p0,
const std::vector<BooleanFunction::Value>& p1)
51 std::vector<BooleanFunction::Value> simplified;
52 simplified.reserve(p0.size());
53 for (
auto i = 0u; i < p0.size(); i++)
55 if ((p0[i] == 0) && (p1[i] == 0))
57 simplified.emplace_back(BooleanFunction::Value::ZERO);
59 else if ((p0[i] == 1) || (p1[i] == 1))
61 simplified.emplace_back(BooleanFunction::Value::ONE);
65 simplified.emplace_back(BooleanFunction::Value::X);
79 std::vector<BooleanFunction::Value> simplified;
80 simplified.reserve(p.size());
81 for (
const auto& value : p)
83 if (value == BooleanFunction::Value::ZERO)
85 simplified.emplace_back(BooleanFunction::Value::ONE);
87 else if (value == BooleanFunction::Value::ONE)
89 simplified.emplace_back(BooleanFunction::Value::ZERO);
93 simplified.emplace_back(value);
106 BooleanFunction Xor(
const std::vector<BooleanFunction::Value>& p0,
const std::vector<BooleanFunction::Value>& p1)
108 std::vector<BooleanFunction::Value> simplified;
109 simplified.reserve(p0.size());
110 for (
auto i = 0u; i < p0.size(); i++)
112 if (((p0[i] == 0) && (p1[i] == 1)) || ((p0[i] == 1) && (p1[i] == 0)))
114 simplified.emplace_back(BooleanFunction::Value::ONE);
116 else if (((p0[i] == 0) && (p1[i] == 0)) || ((p0[i] == 1) && (p1[i] == 1)))
118 simplified.emplace_back(BooleanFunction::Value::ZERO);
122 simplified.emplace_back(BooleanFunction::Value::X);
135 BooleanFunction Add(
const std::vector<BooleanFunction::Value>& p0,
const std::vector<BooleanFunction::Value>& p1)
137 if (std::any_of(p0.begin(), p0.end(), [](
auto val) { return val == BooleanFunction::Value::X || val == BooleanFunction::Value::Z; })
138 || std::any_of(p1.begin(), p1.end(), [](
auto val) { return val == BooleanFunction::Value::X || val == BooleanFunction::Value::Z; }))
143 std::vector<BooleanFunction::Value> simplified;
144 simplified.reserve(p0.size());
145 auto carry = BooleanFunction::Value::ZERO;
146 for (
auto i = 0u; i < p0.size(); i++)
148 auto res = p0[i] + p1[i] +
carry;
162 BooleanFunction Sub(
const std::vector<BooleanFunction::Value>& p0,
const std::vector<BooleanFunction::Value>& p1)
164 if (std::any_of(p0.begin(), p0.end(), [](
auto val) { return val == BooleanFunction::Value::X || val == BooleanFunction::Value::Z; })
165 || std::any_of(p1.begin(), p1.end(), [](
auto val) { return val == BooleanFunction::Value::X || val == BooleanFunction::Value::Z; }))
170 std::vector<BooleanFunction::Value> simplified;
171 simplified.reserve(p0.size());
172 auto carry = BooleanFunction::Value::ONE;
173 for (
auto i = 0u; i < p0.size(); i++)
175 auto res = p0[i] + !(p1[i]) +
carry;
189 BooleanFunction Mul(
const std::vector<BooleanFunction::Value>& p0,
const std::vector<BooleanFunction::Value>& p1)
191 if (std::any_of(p0.begin(), p0.end(), [](
auto val) { return val == BooleanFunction::Value::X || val == BooleanFunction::Value::Z; })
192 || std::any_of(p1.begin(), p1.end(), [](
auto val) { return val == BooleanFunction::Value::X || val == BooleanFunction::Value::Z; }))
197 auto bitsize = p0.size();
198 std::vector<BooleanFunction::Value> simplified(bitsize, BooleanFunction::Value::ZERO);
199 for (
auto i = 0u; i < bitsize; i++)
201 auto carry = BooleanFunction::Value::ZERO;
202 for (
auto j = 0u; j < bitsize - i; j++)
204 auto res = simplified[i + j] + (p0[i] & p1[j]) +
carry;
219 BooleanFunction Sle(
const std::vector<BooleanFunction::Value>& p0,
const std::vector<BooleanFunction::Value>& p1)
221 if (std::any_of(p0.begin(), p0.end(), [](
auto val) { return val == BooleanFunction::Value::X || val == BooleanFunction::Value::Z; })
222 || std::any_of(p1.begin(), p1.end(), [](
auto val) { return val == BooleanFunction::Value::X || val == BooleanFunction::Value::Z; }))
227 auto msb_p0 = p0.back();
228 auto msb_p1 = p1.back();
229 if (msb_p0 == BooleanFunction::Value::ONE && msb_p1 == BooleanFunction::Value::ZERO)
233 else if (msb_p0 == BooleanFunction::Value::ZERO && msb_p1 == BooleanFunction::Value::ONE)
238 std::vector<BooleanFunction::Value> simplified;
242 for (
auto i = 0u; i < p0.size(); i++)
244 res = p0[i] + !(p1[i]) +
carry;
259 BooleanFunction Slt(
const std::vector<BooleanFunction::Value>& p0,
const std::vector<BooleanFunction::Value>& p1)
261 if (std::any_of(p0.begin(), p0.end(), [](
auto val) { return val == BooleanFunction::Value::X || val == BooleanFunction::Value::Z; })
262 || std::any_of(p1.begin(), p1.end(), [](
auto val) { return val == BooleanFunction::Value::X || val == BooleanFunction::Value::Z; }))
267 auto msb_p0 = p0.back();
268 auto msb_p1 = p1.back();
269 if (msb_p0 == BooleanFunction::Value::ONE && msb_p1 == BooleanFunction::Value::ZERO)
273 else if (msb_p0 == BooleanFunction::Value::ZERO && msb_p1 == BooleanFunction::Value::ONE)
278 std::vector<BooleanFunction::Value> simplified;
281 for (
auto i = 0u; i < p0.size(); i++)
283 res = p0[i] + !(p1[i]) +
carry;
284 carry = (res >> 1) & 1;
297 BooleanFunction Ule(
const std::vector<BooleanFunction::Value>& p0,
const std::vector<BooleanFunction::Value>& p1)
299 if (std::any_of(p0.begin(), p0.end(), [](
auto val) { return val == BooleanFunction::Value::X || val == BooleanFunction::Value::Z; })
300 || std::any_of(p1.begin(), p1.end(), [](
auto val) { return val == BooleanFunction::Value::X || val == BooleanFunction::Value::Z; }))
305 for (
i32 i = p0.size() - 1; i >= 0; i--)
307 if (p0[i] == BooleanFunction::Value::ONE && p1[i] == BooleanFunction::Value::ZERO)
311 else if (p0[i] == BooleanFunction::Value::ZERO && p1[i] == BooleanFunction::Value::ONE)
326 BooleanFunction Ult(
const std::vector<BooleanFunction::Value>& p0,
const std::vector<BooleanFunction::Value>& p1)
328 if (std::any_of(p0.begin(), p0.end(), [](
auto val) { return val == BooleanFunction::Value::X || val == BooleanFunction::Value::Z; })
329 || std::any_of(p1.begin(), p1.end(), [](
auto val) { return val == BooleanFunction::Value::X || val == BooleanFunction::Value::Z; }))
334 for (
i32 i = p0.size() - 1; i >= 0; i--)
336 if (p0[i] == BooleanFunction::Value::ONE && p1[i] == BooleanFunction::Value::ZERO)
340 else if (p0[i] == BooleanFunction::Value::ZERO && p1[i] == BooleanFunction::Value::ONE)
356 BooleanFunction Ite(
const std::vector<BooleanFunction::Value>& p0,
const std::vector<BooleanFunction::Value>& p1,
const std::vector<BooleanFunction::Value>& p2)
358 if (p0.front() == BooleanFunction::Value::ONE)
362 else if (p0.front() == BooleanFunction::Value::ZERO)
381 std::vector<std::vector<BooleanFunction::Value>> values;
382 for (
const auto& parameter : p)
384 values.emplace_back(parameter.get_top_level_node().constant);
390 return OK(
And(values[0], values[1]));
392 return OK(
Or(values[0], values[1]));
394 return OK(
Not(values[0]));
396 return OK(
Xor(values[0], values[1]));
398 return OK(
Add(values[0], values[1]));
400 return OK(
Sub(values[0], values[1]));
402 return OK(
Mul(values[0], values[1]));
443 return ERR(
"could not propagate constants: not implemented for given node type");
455 bool is_x_y(
const z3::expr&
x,
const z3::expr&
y)
457 if (
x.id() ==
y.id())
473 bool is_x_not_y(
const z3::expr&
x,
const z3::expr&
y)
475 const auto x_kind =
x.decl().decl_kind();
476 const auto y_kind =
y.decl().decl_kind();
478 if (x_kind == Z3_OP_BNOT || x_kind == Z3_OP_NOT)
480 if (is_x_y(
x.arg(0),
y))
485 if (y_kind == Z3_OP_BNOT || y_kind == Z3_OP_NOT)
487 if (is_x_y(
y.arg(0),
x))
499 std::vector<z3::expr> get_parameters(
const z3::expr& e)
501 std::vector<z3::expr> p;
502 for (
u32 i = 0; i < e.num_args(); i++)
504 p.push_back(e.arg(i));
513 bool is_ones(
const z3::expr& e)
520 const std::string val_str = Z3_get_numeral_binary_string(e.ctx(), e);
523 return val_str.find(
'0') == std::string::npos;
529 bool is_zero(
const z3::expr& e)
536 const std::string val_str = Z3_get_numeral_binary_string(e.ctx(), e);
539 return val_str.find(
'1') == std::string::npos;
553 if (e.get_sort().bv_size() > 64)
558 return e.get_numeral_uint64() == val;
564 bool is_kind(
const z3::expr& e,
const Z3_decl_kind& t)
566 return e.decl().decl_kind() == t;
572 bool is_commutative(
const Z3_decl_kind& t)
620 log_error(
"z3_utils",
"commutative check not implemeted for type {}!",
static_cast<int>(t));
629 std::vector<z3::expr> normalize(std::vector<z3::expr>&& p)
636 std::sort(p.begin(), p.end(), [](
const auto& lhs,
const auto& rhs) { return lhs.decl().decl_kind() > rhs.decl().decl_kind(); });
643 bool check_simplification_for_correctness(
const z3::expr& org,
const z3::expr& smp)
645 log_warning(
"z3_utils",
"Checking simplification for correctness. This is slow and expensive!");
647 z3::solver s(org.ctx());
649 const auto r = s.check();
653 std::cout <<
"Correctness Check failed!!!" << std::endl;
654 std::cout <<
"ORG: " << org << std::endl;
655 std::cout <<
"NEW: " << smp << std::endl;
666 std::vector<z3::expr> simplify_concat(z3::context& ctx,
const z3::expr& p0,
const z3::expr& p1)
668 const u64 p0_size = p0.get_sort().bv_size();
669 const u64 p1_size = p1.get_sort().bv_size();
673 if (p0.is_numeral() && p1.is_numeral())
675 if ((p0_size + p1_size) <= 64)
677 return {ctx.bv_val((p1.get_numeral_uint64() << p0_size) + p0.get_numeral_uint64(), p0_size + p1_size)};
681 if (is_kind(p0, Z3_OP_EXTRACT) && is_kind(p1, Z3_OP_EXTRACT))
683 auto p0_parameter = get_parameters(p0);
684 auto p1_parameter = get_parameters(p1);
686 if (is_x_y(p0_parameter[0], p1_parameter[0]))
689 if (p1.lo() == (p0.hi() + 1))
691 const auto res = p0_parameter[0].extract(p1.hi(), p0.lo());
696 if ((p1.lo() == p1.hi()) && (p1.lo() == p0.hi()))
698 const auto res = z3::expr(ctx, Z3_mk_sign_ext(ctx, 1, p0));
704 if (is_kind(p0, Z3_OP_EXTRACT) && p1.is_numeral())
709 const auto res = z3::expr(ctx, Z3_mk_zero_ext(ctx, p1_size, p0));
714 if (is_kind(p0, Z3_OP_SIGN_EXT) && is_kind(p1, Z3_OP_EXTRACT))
716 auto p0_parameter = get_parameters(p0);
717 auto p1_parameter = get_parameters(p1);
718 auto p00_parameter = get_parameters(p0_parameter[0]);
720 if (is_x_y(p00_parameter[0], p1_parameter[0]))
723 if ((p1.lo() == p1.hi()) && (p1.lo() == p0_parameter[0].hi()))
725 const u32 extend_by = p0.get_sort().bv_size() - p0_parameter[0].get_sort().bv_size() + 1;
726 auto res = z3::expr(ctx, Z3_mk_sign_ext(ctx, extend_by, p0_parameter[0]));
732 if (is_kind(p0, Z3_OP_ZERO_EXT) && p1.is_numeral())
734 auto p0_parameter = get_parameters(p0);
739 const u32 extend_by = p0.get_sort().bv_size() - p0_parameter[0].get_sort().bv_size() + p1_size;
740 const auto res = z3::expr(ctx, Z3_mk_zero_ext(ctx, extend_by, p0_parameter[0]));
752 Result<z3::expr> simplify_internal(
const z3::expr& e, std::unordered_map<u32, z3::expr>& cache,
const bool check_correctness)
754 if (
const auto it = cache.find(e.id()); it != cache.end())
756 return OK(it->second);
766 else if (e.is_const())
774 size = e.get_sort().bv_size();
780 const auto op = e.decl().decl_kind();
781 std::vector<z3::expr> p;
782 for (
u32 i = 0; i < e.num_args(); i++)
784 const auto arg = e.arg(i);
786 const auto res = simplify_internal(arg, cache, check_correctness);
790 if (check_correctness && !check_simplification_for_correctness(arg, res.get()))
792 return ERR(
"simplification failed correctness check!");
795 const auto [it, _] = cache.insert({arg.id(), res.get()});
796 p.push_back(it->second);
800 return ERR(res.get_error());
805 if (!p.empty() && std::all_of(p.begin(), p.end(), [](
const auto& p_e) { return p_e.is_numeral() && p_e.is_bv(); }))
809 std::vector<BooleanFunction> p_bf;
810 for (
const auto& p_e : p)
819 return ERR_APPEND(res.get_error(),
"could not simplify sub-expression in abstract syntax tree: constant propagation failed");
822 auto bf_c = res.get();
823 if (!bf_c.is_empty())
831 if (is_commutative(op))
833 p = normalize(std::move(p));
849 if (p[1].is_bool() && p[1].is_false())
851 return OK(ctx.bool_val(
false));
854 if (p[1].is_bool() && p[1].is_true())
859 if (is_x_y(p[0], p[1]))
864 if (is_x_not_y(p[0], p[1]))
866 return OK(ctx.bool_val(
false));
869 if (p[0].is_or() && p[1].is_or())
871 auto p0_parameter = get_parameters(p[0]);
872 auto p1_parameter = get_parameters(p[1]);
875 if (is_x_y(p0_parameter[0], p1_parameter[0]))
877 return OK(p0_parameter[0] | (p0_parameter[1] & p1_parameter[1]));
880 if (is_x_y(p0_parameter[0], p1_parameter[1]))
882 return OK(p0_parameter[0] | (p0_parameter[1] & p1_parameter[0]));
886 if (is_x_y(p0_parameter[1], p1_parameter[0]))
888 return OK(p0_parameter[1] | (p0_parameter[0] & p1_parameter[1]));
891 if (is_x_y(p0_parameter[1], p1_parameter[1]))
893 return OK(p0_parameter[1] | (p0_parameter[0] & p1_parameter[0]));
899 auto p1_parameter = get_parameters(p[1]);
901 if (is_x_y(p[0], p1_parameter[1]))
906 if (is_x_y(p[0], p1_parameter[0]))
912 if (is_x_not_y(p1_parameter[0], p[0]))
914 return OK(ctx.bool_val(
false));
917 if (is_x_not_y(p1_parameter[1], p[0]))
919 return OK(ctx.bool_val(
false));
925 auto p1_parameter = get_parameters(p[1]);
928 if (is_x_y(p1_parameter[0], p[0]))
933 if (is_x_y(p1_parameter[1], p[0]))
938 if (is_x_not_y(p1_parameter[0], p[0]))
940 return OK(p[0] & p1_parameter[1]);
943 if (is_x_not_y(p1_parameter[1], p[0]))
945 return OK(p[0] & p1_parameter[0]);
951 auto p0_parameter = get_parameters(p[0]);
954 if (is_x_y(p0_parameter[0], p[1]))
960 if (is_x_y(p0_parameter[1], p[1]))
965 if (is_x_not_y(p0_parameter[0], p[1]))
967 return OK(ctx.bool_val(
false));
970 if (is_x_not_y(p0_parameter[1], p[1]))
972 return OK(ctx.bool_val(
false));
978 auto p0_parameter = get_parameters(p[0]);
981 if (is_x_y(p0_parameter[0], p[1]))
986 if (is_x_y(p0_parameter[1], p[1]))
991 if (is_x_not_y(p0_parameter[0], p[1]))
993 return OK(p[1] & p0_parameter[1]);
996 if (is_x_not_y(p0_parameter[1], p[1]))
998 return OK(p[1] & p0_parameter[0]);
1002 return OK(p[0] & p[1]);
1007 if (p[1].is_false())
1019 if (is_x_y(p[0], p[1]))
1025 if (is_x_not_y(p[0], p[1]))
1027 return OK(ctx.bool_val(
true));
1030 if (p[0].is_and() && p[1].is_and())
1032 auto p0_parameter = get_parameters(p[0]);
1033 auto p1_parameter = get_parameters(p[1]);
1036 if (is_x_y(p0_parameter[0], p1_parameter[0]))
1038 return OK(p0_parameter[0] & (p0_parameter[1] | p1_parameter[1]));
1041 if (is_x_y(p0_parameter[0], p1_parameter[1]))
1043 return OK(p0_parameter[0] & (p0_parameter[1] | p1_parameter[0]));
1046 if (is_x_y(p0_parameter[1], p1_parameter[0]))
1048 return OK(p0_parameter[1] & (p0_parameter[0] | p1_parameter[1]));
1051 if (is_x_y(p0_parameter[1], p1_parameter[1]))
1053 return OK(p0_parameter[1] & (p0_parameter[0] | p1_parameter[0]));
1059 auto p1_parameter = get_parameters(p[1]);
1061 if (is_x_not_y(p1_parameter[1], p[0]))
1063 return OK(p[0] | p1_parameter[0]);
1067 if ((is_x_y(p1_parameter[0], p[0])) || (is_x_y(p1_parameter[1], p[0])))
1073 if (is_x_not_y(p1_parameter[0], p[0]))
1075 return OK(p[0] | p1_parameter[1]);
1078 if (is_x_not_y(p1_parameter[1], p[0]))
1080 return OK(p[0] | p1_parameter[0]);
1086 auto p1_parameter = get_parameters(p[1]);
1089 if (is_x_y(p1_parameter[0], p[0]))
1094 if (is_x_y(p1_parameter[1], p[0]))
1100 if (is_x_not_y(p1_parameter[0], p[0]))
1102 return OK(ctx.bool_val(
true));
1106 if (is_x_not_y(p1_parameter[1], p[0]))
1108 return OK(ctx.bool_val(
true));
1114 auto p0_parameter = get_parameters(p[0]);
1117 if (is_x_y(p0_parameter[0], p[1]))
1122 if (is_x_y(p0_parameter[1], p[1]))
1128 if (is_x_not_y(p0_parameter[0], p[1]))
1130 return OK(ctx.bool_val(
true));
1134 if (is_x_not_y(p0_parameter[1], p[1]))
1136 return OK(ctx.bool_val(
true));
1142 auto p0_parameter = get_parameters(p[0]);
1145 if (is_x_y(p0_parameter[0], p[1]))
1150 if (is_x_y(p0_parameter[1], p[1]))
1156 if (is_x_not_y(p0_parameter[0], p[1]))
1158 return OK(p0_parameter[1] | p[1]);
1162 if (is_x_not_y(p0_parameter[1], p[1]))
1164 return OK(p0_parameter[0] | p[1]);
1168 if (p[0].is_eq() && p[1].is_eq())
1170 auto p0_parameter = get_parameters(p[0]);
1171 auto p1_parameter = get_parameters(p[1]);
1174 if (p0_parameter[0].get_sort().is_bv() && is_x_y(p0_parameter[0], p1_parameter[0]))
1176 if (p0_parameter[0].get_sort().bv_size() == 1)
1178 if (is_ones(p0_parameter[1]) && is_zero(p1_parameter[1]))
1180 return OK(ctx.bool_val(
true));
1183 if (is_zero(p0_parameter[1]) && is_ones(p1_parameter[1]))
1185 return OK(ctx.bool_val(
true));
1191 return OK(p[0] | p[1]);
1198 return OK(get_parameters(p[0])[0]);
1202 if (is_kind(p[0], Z3_OP_BAND))
1204 auto p0_parameter = get_parameters(p[0]);
1205 if (p0_parameter[0].is_not() && p0_parameter[1].is_not())
1207 return OK(get_parameters(p0_parameter[0])[0] | get_parameters(p0_parameter[1])[0]);
1212 if (is_kind(p[0], Z3_OP_BOR))
1214 auto p0_parameter = get_parameters(p[0]);
1215 if (p0_parameter[0].is_not() && p0_parameter[1].is_not())
1217 return OK(get_parameters(p0_parameter[0])[0] & get_parameters(p0_parameter[1])[0]);
1224 auto p0_parameter = get_parameters(p[0]);
1225 return OK((~p0_parameter[0]) & (~p0_parameter[1]));
1231 auto p0_parameter = get_parameters(p[0]);
1232 return OK((~p0_parameter[0]) | (~p0_parameter[1]));
1244 return OK(ctx.bv_val(0,
size));
1252 if (is_x_y(p[0], p[1]))
1257 if (is_x_not_y(p[0], p[1]))
1259 return OK(ctx.bv_val(0,
size));
1262 if (is_kind(p[0], Z3_OP_BOR) && is_kind(p[1], Z3_OP_BOR))
1264 auto p0_parameter = get_parameters(p[0]);
1265 auto p1_parameter = get_parameters(p[1]);
1268 if (is_x_y(p0_parameter[0], p1_parameter[0]))
1270 return OK(p0_parameter[0] | (p0_parameter[1] & p1_parameter[1]));
1273 if (is_x_y(p0_parameter[0], p1_parameter[1]))
1275 return OK(p0_parameter[0] | (p0_parameter[1] & p1_parameter[0]));
1279 if (is_x_y(p0_parameter[1], p1_parameter[0]))
1281 return OK(p0_parameter[1] | (p0_parameter[0] & p1_parameter[1]));
1284 if (is_x_y(p0_parameter[1], p1_parameter[1]))
1286 return OK(p0_parameter[1] | (p0_parameter[0] & p1_parameter[0]));
1290 if (is_kind(p[1], Z3_OP_BAND))
1292 auto p1_parameter = get_parameters(p[1]);
1294 if (is_x_y(p[0], p1_parameter[1]))
1299 if (is_x_y(p[0], p1_parameter[0]))
1305 if (is_x_not_y(p1_parameter[0], p[0]))
1307 return OK(ctx.bv_val(0,
size));
1310 if (is_x_not_y(p1_parameter[1], p[0]))
1312 return OK(ctx.bv_val(0,
size));
1316 if (is_kind(p[1], Z3_OP_BOR))
1318 auto p1_parameter = get_parameters(p[1]);
1321 if (is_x_y(p1_parameter[0], p[0]))
1326 if (is_x_y(p1_parameter[1], p[0]))
1331 if (is_x_not_y(p1_parameter[0], p[0]))
1333 return OK(p[0] & p1_parameter[1]);
1336 if (is_x_not_y(p1_parameter[1], p[0]))
1338 return OK(p[0] & p1_parameter[0]);
1342 if (is_kind(p[0], Z3_OP_BAND))
1344 auto p0_parameter = get_parameters(p[0]);
1347 if (is_x_y(p0_parameter[0], p[1]))
1353 if (is_x_y(p0_parameter[1], p[1]))
1358 if (is_x_not_y(p0_parameter[0], p[1]))
1360 return OK(ctx.bv_val(0,
size));
1363 if (is_x_not_y(p0_parameter[1], p[1]))
1365 return OK(ctx.bv_val(0,
size));
1369 if (is_kind(p[0], Z3_OP_BOR))
1371 auto p0_parameter = get_parameters(p[0]);
1374 if (is_x_y(p0_parameter[0], p[1]))
1379 if (is_x_y(p0_parameter[1], p[1]))
1384 if (is_x_not_y(p0_parameter[0], p[1]))
1386 return OK(p[1] & p0_parameter[1]);
1389 if (is_x_not_y(p0_parameter[1], p[1]))
1391 return OK(p[1] & p0_parameter[0]);
1395 return OK(p[0] & p[1]);
1399 z3::expr res = p[0] & p[1];
1400 for (
u32 i = 2; i < p.size(); i++)
1409 if (is_kind(p[0], Z3_OP_BNOT))
1411 return OK(get_parameters(p[0])[0]);
1415 if (is_kind(p[0], Z3_OP_BAND))
1417 auto p0_parameter = get_parameters(p[0]);
1418 if (is_kind(p0_parameter[0], Z3_OP_BNOT) && is_kind(p0_parameter[1], Z3_OP_BNOT))
1420 return OK(get_parameters(p0_parameter[0])[0] | get_parameters(p0_parameter[1])[0]);
1425 if (is_kind(p[0], Z3_OP_BOR))
1427 auto p0_parameter = get_parameters(p[0]);
1428 if (is_kind(p0_parameter[0], Z3_OP_BNOT) && is_kind(p0_parameter[1], Z3_OP_BNOT))
1430 return OK(get_parameters(p0_parameter[0])[0] & get_parameters(p0_parameter[1])[0]);
1435 if (is_kind(p[0], Z3_OP_BOR))
1437 auto p0_parameter = get_parameters(p[0]);
1438 return OK((~p0_parameter[0]) & (~p0_parameter[1]));
1442 if (is_kind(p[0], Z3_OP_BAND))
1444 auto p0_parameter = get_parameters(p[0]);
1445 return OK((~p0_parameter[0]) | (~p0_parameter[1]));
1467 if (is_x_y(p[0], p[1]))
1473 if (is_x_not_y(p[0], p[1]))
1475 return OK(ctx.bv_val(-1,
size));
1478 if (is_kind(p[0], Z3_OP_BAND) && is_kind(p[1], Z3_OP_BAND))
1480 auto p0_parameter = get_parameters(p[0]);
1481 auto p1_parameter = get_parameters(p[1]);
1484 if (is_x_y(p0_parameter[0], p1_parameter[0]))
1486 return OK(p0_parameter[0] & (p0_parameter[1] | p1_parameter[1]));
1489 if (is_x_y(p0_parameter[0], p1_parameter[1]))
1491 return OK(p0_parameter[0] & (p0_parameter[1] | p1_parameter[0]));
1494 if (is_x_y(p0_parameter[1], p1_parameter[0]))
1496 return OK(p0_parameter[1] & (p0_parameter[0] | p1_parameter[1]));
1499 if (is_x_y(p0_parameter[1], p1_parameter[1]))
1501 return OK(p0_parameter[1] & (p0_parameter[0] | p1_parameter[0]));
1505 if (is_kind(p[1], Z3_OP_BAND))
1507 auto p1_parameter = get_parameters(p[1]);
1509 if (is_x_not_y(p1_parameter[1], p[0]))
1511 return OK(p[0] | p1_parameter[0]);
1515 if ((is_x_y(p1_parameter[0], p[0])) || (is_x_y(p1_parameter[1], p[0])))
1521 if (is_x_not_y(p1_parameter[0], p[0]))
1523 return OK(p[0] | p1_parameter[1]);
1526 if (is_x_not_y(p1_parameter[1], p[0]))
1528 return OK(p[0] | p1_parameter[0]);
1532 if (is_kind(p[1], Z3_OP_BOR))
1534 auto p1_parameter = get_parameters(p[1]);
1537 if (is_x_y(p1_parameter[0], p[0]))
1542 if (is_x_y(p1_parameter[1], p[0]))
1548 if (is_x_not_y(p1_parameter[0], p[0]))
1550 return OK(ctx.bv_val(-1,
size));
1554 if (is_x_not_y(p1_parameter[1], p[0]))
1556 return OK(ctx.bv_val(-1,
size));
1560 if (is_kind(p[0], Z3_OP_BOR))
1562 auto p0_parameter = get_parameters(p[0]);
1565 if (is_x_y(p0_parameter[0], p[1]))
1570 if (is_x_y(p0_parameter[1], p[1]))
1576 if (is_x_not_y(p0_parameter[0], p[1]))
1578 return OK(ctx.bv_val(-1,
size));
1582 if (is_x_not_y(p0_parameter[1], p[1]))
1584 return OK(ctx.bv_val(-1,
size));
1588 if (is_kind(p[0], Z3_OP_BAND))
1590 auto p0_parameter = get_parameters(p[0]);
1593 if (is_x_y(p0_parameter[0], p[1]))
1598 if (is_x_y(p0_parameter[1], p[1]))
1604 if (is_x_not_y(p0_parameter[0], p[1]))
1606 return OK(p0_parameter[1] | p[1]);
1610 if (is_x_not_y(p0_parameter[1], p[1]))
1612 return OK(p0_parameter[0] | p[1]);
1616 return OK(p[0] | p[1]);
1620 z3::expr res = p[0] | p[1];
1621 for (
u32 i = 2; i < p.size(); i++)
1642 if (is_x_y(p[0], p[1]))
1644 return OK(ctx.bv_val(0,
size));
1647 if (is_x_not_y(p[0], p[1]))
1649 return OK(ctx.bv_val(-1,
size));
1652 return OK(p[0] ^ p[1]);
1656 z3::expr res = p[0] ^ p[1];
1657 for (
u32 i = 2; i < p.size(); i++)
1666 if (is_kind(p[0], Z3_OP_BNEG))
1668 return OK(get_parameters(p[0])[0]);
1683 const u64 p0_size = p[0].get_sort().bv_size();
1684 const u64 p1_size = p[1].get_sort().bv_size();
1686 if (is_kind(p[0], Z3_OP_BNEG))
1688 const auto p0_parameter = get_parameters(p[0]);
1690 return OK(p[1] - p0_parameter[0]);
1693 if (is_kind(p[1], Z3_OP_BNEG))
1695 const auto p1_parameter = get_parameters(p[1]);
1697 return OK(p[0] - p1_parameter[0]);
1701 if ((is_kind(p[0], Z3_OP_EXTRACT)) && is_kind(p[1], Z3_OP_EXTRACT))
1703 if ((p[0].lo() == 0) && (p[0].hi() == 0) && (p[1].lo() == 0) && (p[1].hi() == 0))
1705 auto p0_parameter = get_parameters(p[0]);
1706 auto p1_parameter = get_parameters(p[1]);
1708 return OK((p0_parameter[0] + p1_parameter[0]).extract(0, 0));
1712 return OK(p[0] + p[1]);
1716 z3::expr
sum = p[0] + p[1];
1717 for (
u32 i = 2; i < p.size(); i++)
1733 if (is_x_y(p[0], p[1]))
1735 return OK(ctx.bv_val(0,
size));
1739 if (is_kind(p[1], Z3_OP_BNEG))
1741 const auto p1_parameter = get_parameters(p[1]);
1743 return OK(p[0] + p1_parameter[0]);
1746 return OK(p[0] - p[1]);
1750 z3::expr
sum = p[0] - p[1];
1751 for (
u32 i = 2; i < p.size(); i++)
1762 return OK(ctx.bv_val(0,
size));
1777 return OK(p[0] * p[1]);
1787 if (is_x_y(p[0], p[1]))
1789 return OK(ctx.bv_val(1,
size));
1792 return OK(p[0] / p[1]);
1802 if (is_x_y(p[0], p[1]))
1804 return OK(ctx.bv_val(1,
size));
1807 return OK(z3::expr(ctx, Z3_mk_bvudiv(ctx, p[0], p[1])));
1814 return OK(ctx.bv_val(0,
size));
1817 if (is_x_y(p[0], p[1]))
1819 return OK(ctx.bv_val(0,
size));
1822 return OK(z3::expr(ctx, Z3_mk_bvsrem(ctx, p[0], p[1])));
1829 return OK(ctx.bv_val(0,
size));
1832 if (is_x_y(p[0], p[1]))
1834 return OK(ctx.bv_val(0,
size));
1837 return OK(z3::expr(ctx, Z3_mk_bvurem(ctx, p[0], p[1])));
1840 case Z3_OP_EXTRACT: {
1842 if ((e.lo() == 0) && (e.hi() == 0) && (p[0].get_sort().bv_size() == 1))
1848 if (((e.hi() - e.lo()) == (p[0].get_sort().bv_size() - 1)) && (e.lo() == 0))
1854 if (p[0].is_numeral())
1856 const std::string p0_str = Z3_get_numeral_binary_string(e.ctx(), p[0]);
1857 const std::string p0_pad = std::string(p[0].get_sort().bv_size() - p0_str.length(),
'0') + p0_str;
1860 std::string p0_rev = p0_pad;
1861 std::reverse(p0_rev.begin(), p0_rev.end());
1863 const std::string ex_str = p0_rev.substr(e.lo(), e.hi() - e.lo() + 1);
1870 return OK(p[0].extract(e.hi(), e.lo()));
1873 case Z3_OP_CONCAT: {
1874 std::vector<z3::expr> q = {p.begin(), p.end()};
1875 std::vector<z3::expr> res;
1877 while (q.size() > 1)
1879 const auto p0 = q.back();
1882 const auto p1 = q.back();
1885 const auto sc = simplify_concat(ctx, p0, p1);
1889 q.push_back(sc.front());
1893 res.insert(res.begin(), sc.back());
1894 q.push_back(sc.front());
1898 res.push_back(q.front());
1902 z3::expr_vector res_e(ctx);
1903 for (
const auto& e : res)
1908 return OK(z3::concat(res_e));
1911 return OK(res.front());
1914 case Z3_OP_ZERO_EXT: {
1915 const u64 i = e.get_sort().bv_size() - p[0].get_sort().bv_size();
1916 return OK(z3::expr(ctx, Z3_mk_zero_ext(ctx, i, p[0])));
1919 case Z3_OP_SIGN_EXT: {
1920 const u64 i = e.get_sort().bv_size() - p[0].get_sort().bv_size();
1921 return OK(z3::expr(ctx, Z3_mk_sign_ext(ctx, i, p[0])));
1926 if (is_x_y(p[0], p[1]))
1928 return OK(ctx.bool_val(
true));
1932 if (p[0].is_numeral() && p[1].is_numeral())
1934 const std::string p0_str = Z3_get_numeral_binary_string(e.ctx(), p[0]);
1935 const std::string p1_str = Z3_get_numeral_binary_string(e.ctx(), p[1]);
1937 if (p0_str != p1_str)
1939 return OK(ctx.bool_val(
false));
1943 return OK(p[0] == p[1]);
1948 if (is_x_y(p[0], p[1]))
1950 return OK(ctx.bool_val(
true));
1953 return OK(z3::expr(ctx, Z3_mk_bvsle(ctx, p[0], p[1])));
1958 if (is_x_y(p[0], p[1]))
1960 return OK(ctx.bool_val(
false));
1963 return OK(z3::expr(ctx, Z3_mk_bvslt(ctx, p[0], p[1])));
1968 if (is_x_y(p[0], p[1]))
1970 return OK(ctx.bool_val(
true));
1973 return OK(z3::expr(ctx, Z3_mk_bvule(ctx, p[0], p[1])));
1980 return OK(ctx.bool_val(
false));
1983 if (is_x_y(p[0], p[1]))
1985 return OK(ctx.bool_val(
false));
1988 return OK(z3::expr(ctx, Z3_mk_bvult(ctx, p[0], p[1])));
1993 if (p[0].is_false())
2003 if (is_x_y(p[1], p[2]))
2008 return OK(z3::ite(p[0], p[1], p[2]));
2012 return ERR(
"could not simplify sub-expression in abstract syntax tree: not implemented for given node type " + std::to_string(op));
2022 const u32 max_loop_iterations = 128;
2026 z3::expr prev_res = res;
2031 const auto simplify_res = simplify_internal(res, cache, check_correctness);
2032 if (simplify_res.is_error())
2034 return simplify_res;
2036 const auto [it, _] = cache.insert({e.id(), simplify_res.get()});
2040 if (iteration > max_loop_iterations)
2042 return ERR(
"Triggered max iteration counter during simplificaton!");
2044 }
while (!z3::eq(prev_res, res));
2046 if (check_correctness && !check_simplification_for_correctness(e, res))
2048 return ERR(
"Simplification failed");
2056 std::unordered_map<u32, z3::expr> cache;
Value
represents the type of the node
static BooleanFunction Const(const BooleanFunction::Value &value)
#define log_error(channel,...)
#define log_warning(channel,...)
#define ERR_APPEND(prev_error, message)
BooleanFunction And(const std::vector< BooleanFunction::Value > &p0, const std::vector< BooleanFunction::Value > &p1)
BooleanFunction Sub(const std::vector< BooleanFunction::Value > &p0, const std::vector< BooleanFunction::Value > &p1)
BooleanFunction Ult(const std::vector< BooleanFunction::Value > &p0, const std::vector< BooleanFunction::Value > &p1)
BooleanFunction Sle(const std::vector< BooleanFunction::Value > &p0, const std::vector< BooleanFunction::Value > &p1)
Result< BooleanFunction > constant_propagation(const BooleanFunction::Node &node, std::vector< BooleanFunction > &&p)
BooleanFunction Ule(const std::vector< BooleanFunction::Value > &p0, const std::vector< BooleanFunction::Value > &p1)
BooleanFunction Mul(const std::vector< BooleanFunction::Value > &p0, const std::vector< BooleanFunction::Value > &p1)
BooleanFunction Add(const std::vector< BooleanFunction::Value > &p0, const std::vector< BooleanFunction::Value > &p1)
BooleanFunction Or(const std::vector< BooleanFunction::Value > &p0, const std::vector< BooleanFunction::Value > &p1)
BooleanFunction Slt(const std::vector< BooleanFunction::Value > &p0, const std::vector< BooleanFunction::Value > &p1)
BooleanFunction Xor(const std::vector< BooleanFunction::Value > &p0, const std::vector< BooleanFunction::Value > &p1)
BooleanFunction Not(const std::vector< BooleanFunction::Value > &p)
BooleanFunction Ite(const std::vector< BooleanFunction::Value > &p0, const std::vector< BooleanFunction::Value > &p1, const std::vector< BooleanFunction::Value > &p2)
bool has_constant_value(const z3::expr &e, const u64 &val)
Result< z3::expr > simplify_local(const z3::expr &e, std::unordered_map< u32, z3::expr > &cache, const bool check_correctness=false)
Applies hand-crafted simplification rules iteratively until no further simplifications can be made.
z3::expr from_bf(const BooleanFunction &bf, z3::context &ctx, const std::map< std::string, z3::expr > &var2expr={})
Result< z3::expr > value_from_binary_string(z3::context &ctx, const std::string &bit_string)
Result< BooleanFunction > to_bf(const z3::expr &e)
u16 type
The type of the node.
static constexpr u16 Srem
static constexpr u16 Udiv
static constexpr u16 Sdiv
static constexpr u16 Urem
static constexpr u16 Sext
static constexpr u16 Concat
static constexpr u16 Slice
static constexpr u16 Zext