8 namespace ConstantPropagation
15 std::vector<BooleanFunction::Value> to_values(
u64 value,
u16 size)
17 std::vector<BooleanFunction::Value> res;
21 res.emplace_back(((value >> i) & 1) ? BooleanFunction::Value::ONE : BooleanFunction::Value::ZERO);
33 std::vector<BooleanFunction::Value>
And(
const std::vector<BooleanFunction::Value>& p0,
const std::vector<BooleanFunction::Value>& p1)
35 std::vector<BooleanFunction::Value> simplified;
36 simplified.reserve(p0.size());
37 for (
auto i = 0u; i < p0.size(); i++)
39 if ((p0[i] == 0) || (p1[i] == 0))
41 simplified.emplace_back(BooleanFunction::Value::ZERO);
43 else if ((p0[i] == 1) && (p1[i] == 1))
45 simplified.emplace_back(BooleanFunction::Value::ONE);
49 simplified.emplace_back(BooleanFunction::Value::X);
62 std::vector<BooleanFunction::Value>
Or(
const std::vector<BooleanFunction::Value>& p0,
const std::vector<BooleanFunction::Value>& p1)
64 std::vector<BooleanFunction::Value> simplified;
65 simplified.reserve(p0.size());
66 for (
auto i = 0u; i < p0.size(); i++)
68 if ((p0[i] == 0) && (p1[i] == 0))
70 simplified.emplace_back(BooleanFunction::Value::ZERO);
72 else if ((p0[i] == 1) || (p1[i] == 1))
74 simplified.emplace_back(BooleanFunction::Value::ONE);
78 simplified.emplace_back(BooleanFunction::Value::X);
90 std::vector<BooleanFunction::Value>
Not(
const std::vector<BooleanFunction::Value>& p)
92 std::vector<BooleanFunction::Value> simplified;
93 simplified.reserve(p.size());
94 for (
const auto& value : p)
96 if (value == BooleanFunction::Value::ZERO)
98 simplified.emplace_back(BooleanFunction::Value::ONE);
100 else if (value == BooleanFunction::Value::ONE)
102 simplified.emplace_back(BooleanFunction::Value::ZERO);
106 simplified.emplace_back(value);
119 std::vector<BooleanFunction::Value>
Xor(
const std::vector<BooleanFunction::Value>& p0,
const std::vector<BooleanFunction::Value>& p1)
121 std::vector<BooleanFunction::Value> simplified;
122 simplified.reserve(p0.size());
123 for (
auto i = 0u; i < p0.size(); i++)
125 if (((p0[i] == 0) && (p1[i] == 1)) || ((p0[i] == 1) && (p1[i] == 0)))
127 simplified.emplace_back(BooleanFunction::Value::ONE);
129 else if (((p0[i] == 0) && (p1[i] == 0)) || ((p0[i] == 1) && (p1[i] == 1)))
131 simplified.emplace_back(BooleanFunction::Value::ZERO);
135 simplified.emplace_back(BooleanFunction::Value::X);
148 std::vector<BooleanFunction::Value>
Add(
const std::vector<BooleanFunction::Value>& p0,
const std::vector<BooleanFunction::Value>& p1)
150 if (p0.size() <= 64 && p1.size() <= 64)
155 if (a_res.is_ok() && b_res.is_ok())
159 const auto res = a_res.get() + b_res.get();
160 return to_values(res, p0.size());
163 return std::vector<BooleanFunction::Value>(p0.size(), BooleanFunction::Value::X);
166 if (std::any_of(p0.begin(), p0.end(), [](
auto val) { return val == BooleanFunction::Value::X || val == BooleanFunction::Value::Z; })
167 || std::any_of(p1.begin(), p1.end(), [](
auto val) { return val == BooleanFunction::Value::X || val == BooleanFunction::Value::Z; }))
169 return std::vector<BooleanFunction::Value>(p0.size(), BooleanFunction::Value::X);
172 std::vector<BooleanFunction::Value> simplified;
173 simplified.reserve(p0.size());
174 auto carry = BooleanFunction::Value::ZERO;
175 for (
auto i = 0u; i < p0.size(); i++)
177 auto res = p0[i] + p1[i] +
carry;
191 std::vector<BooleanFunction::Value>
Sub(
const std::vector<BooleanFunction::Value>& p0,
const std::vector<BooleanFunction::Value>& p1)
193 if (p0.size() <= 64 && p1.size() <= 64)
198 if (a_res.is_ok() && b_res.is_ok())
202 const auto res = a_res.get() - b_res.get();
203 return to_values(res, p0.size());
206 return std::vector<BooleanFunction::Value>(p0.size(), BooleanFunction::Value::X);
209 if (std::any_of(p0.begin(), p0.end(), [](
auto val) { return val == BooleanFunction::Value::X || val == BooleanFunction::Value::Z; })
210 || std::any_of(p1.begin(), p1.end(), [](
auto val) { return val == BooleanFunction::Value::X || val == BooleanFunction::Value::Z; }))
212 return std::vector<BooleanFunction::Value>(p0.size(), BooleanFunction::Value::X);
215 std::vector<BooleanFunction::Value> simplified;
216 simplified.reserve(p0.size());
217 auto carry = BooleanFunction::Value::ONE;
218 for (
auto i = 0u; i < p0.size(); i++)
220 auto res = p0[i] + !(p1[i]) +
carry;
234 std::vector<BooleanFunction::Value>
Mul(
const std::vector<BooleanFunction::Value>& p0,
const std::vector<BooleanFunction::Value>& p1)
236 if (std::any_of(p0.begin(), p0.end(), [](
auto val) { return val == BooleanFunction::Value::X || val == BooleanFunction::Value::Z; })
237 || std::any_of(p1.begin(), p1.end(), [](
auto val) { return val == BooleanFunction::Value::X || val == BooleanFunction::Value::Z; }))
239 return std::vector<BooleanFunction::Value>(p0.size(), BooleanFunction::Value::X);
242 auto bitsize = p0.size();
243 std::vector<BooleanFunction::Value> simplified(bitsize, BooleanFunction::Value::ZERO);
244 for (
auto i = 0u; i < bitsize; i++)
246 auto carry = BooleanFunction::Value::ZERO;
247 for (
auto j = 0u; j < bitsize - i; j++)
249 auto res = simplified[i + j] + (p0[i] & p1[j]) +
carry;
263 bool is_zero(
const std::vector<BooleanFunction::Value>& value)
265 return std::all_of(value.begin(), value.end(), [](
auto v) { return v == BooleanFunction::Value::ZERO; });
268 bool is_negative(
const std::vector<BooleanFunction::Value>& value)
270 return value.back() == BooleanFunction::Value::ONE;
276 bool greater_equal_unsigned(
const std::vector<BooleanFunction::Value>& p0,
const std::vector<BooleanFunction::Value>& p1)
278 for (
auto i = p0.size(); i-- > 0;)
282 return p0[i] == BooleanFunction::Value::ONE;
291 std::vector<BooleanFunction::Value> subtract(
const std::vector<BooleanFunction::Value>& p0,
const std::vector<BooleanFunction::Value>& p1)
293 std::vector<BooleanFunction::Value> res;
294 res.reserve(p0.size());
297 for (
auto i = 0u; i < p0.size(); i++)
299 const auto difference =
static_cast<int>(p0[i]) -
static_cast<int>(p1[i]) - borrow;
300 borrow = (difference < 0) ? 1 : 0;
309 std::vector<BooleanFunction::Value> negate(
const std::vector<BooleanFunction::Value>& value)
311 return subtract(std::vector<BooleanFunction::Value>(value.size(), BooleanFunction::Value::ZERO), value);
323 std::pair<std::vector<BooleanFunction::Value>, std::vector<BooleanFunction::Value>> divide_unsigned(
const std::vector<BooleanFunction::Value>& dividend,
324 const std::vector<BooleanFunction::Value>& divisor)
326 const auto size = dividend.size();
328 if (is_zero(divisor))
330 return {std::vector<BooleanFunction::Value>(
size, BooleanFunction::Value::ONE), dividend};
334 auto divisor_extended = divisor;
335 divisor_extended.push_back(BooleanFunction::Value::ZERO);
337 std::vector<BooleanFunction::Value> quotient(
size, BooleanFunction::Value::ZERO);
338 std::vector<BooleanFunction::Value> remainder(
size + 1, BooleanFunction::Value::ZERO);
340 for (
auto i =
size; i-- > 0;)
342 for (
auto j = remainder.size(); j-- > 1;)
344 remainder[j] = remainder[j - 1];
346 remainder[0] = dividend[i];
348 if (greater_equal_unsigned(remainder, divisor_extended))
350 remainder = subtract(remainder, divisor_extended);
351 quotient[i] = BooleanFunction::Value::ONE;
355 remainder.pop_back();
356 return {quotient, remainder};
359 bool any_undefined(
const std::vector<BooleanFunction::Value>& value)
361 return std::any_of(value.begin(), value.end(), [](
auto v) { return v == BooleanFunction::Value::X || v == BooleanFunction::Value::Z; });
375 std::vector<BooleanFunction::Value>
Eq(
const std::vector<BooleanFunction::Value>& p0,
const std::vector<BooleanFunction::Value>& p1)
377 auto undefined =
false;
378 for (
auto i = 0u; i < p0.size(); i++)
380 if ((p0[i] == BooleanFunction::Value::X) || (p0[i] == BooleanFunction::Value::Z) || (p1[i] == BooleanFunction::Value::X) || (p1[i] == BooleanFunction::Value::Z))
384 else if (p0[i] != p1[i])
386 return std::vector<BooleanFunction::Value>({BooleanFunction::Value::ZERO});
390 return undefined ? std::vector<BooleanFunction::Value>({BooleanFunction::Value::X}) : std::vector<BooleanFunction::Value>({BooleanFunction::Value::ONE});
400 std::vector<BooleanFunction::Value>
Udiv(
const std::vector<BooleanFunction::Value>& p0,
const std::vector<BooleanFunction::Value>& p1)
402 if (any_undefined(p0) || any_undefined(p1))
404 return std::vector<BooleanFunction::Value>(p0.size(), BooleanFunction::Value::X);
407 return divide_unsigned(p0, p1).first;
417 std::vector<BooleanFunction::Value>
Urem(
const std::vector<BooleanFunction::Value>& p0,
const std::vector<BooleanFunction::Value>& p1)
419 if (any_undefined(p0) || any_undefined(p1))
421 return std::vector<BooleanFunction::Value>(p0.size(), BooleanFunction::Value::X);
424 return divide_unsigned(p0, p1).second;
436 std::vector<BooleanFunction::Value>
Sdiv(
const std::vector<BooleanFunction::Value>& p0,
const std::vector<BooleanFunction::Value>& p1)
438 if (any_undefined(p0) || any_undefined(p1))
440 return std::vector<BooleanFunction::Value>(p0.size(), BooleanFunction::Value::X);
443 const auto dividend_negative = is_negative(p0), divisor_negative = is_negative(p1);
445 if (!dividend_negative && !divisor_negative)
447 return divide_unsigned(p0, p1).first;
449 if (dividend_negative && !divisor_negative)
451 return negate(divide_unsigned(negate(p0), p1).first);
453 if (!dividend_negative && divisor_negative)
455 return negate(divide_unsigned(p0, negate(p1)).first);
457 return divide_unsigned(negate(p0), negate(p1)).first;
469 std::vector<BooleanFunction::Value>
Srem(
const std::vector<BooleanFunction::Value>& p0,
const std::vector<BooleanFunction::Value>& p1)
471 if (any_undefined(p0) || any_undefined(p1))
473 return std::vector<BooleanFunction::Value>(p0.size(), BooleanFunction::Value::X);
476 const auto dividend_negative = is_negative(p0), divisor_negative = is_negative(p1);
478 if (!dividend_negative && !divisor_negative)
480 return divide_unsigned(p0, p1).second;
482 if (dividend_negative && !divisor_negative)
484 return negate(divide_unsigned(negate(p0), p1).second);
486 if (!dividend_negative && divisor_negative)
488 return divide_unsigned(p0, negate(p1)).second;
490 return negate(divide_unsigned(negate(p0), negate(p1)).second);
500 std::vector<BooleanFunction::Value>
Shl(
const std::vector<BooleanFunction::Value>& p0,
const u16 p1)
505 return std::vector<BooleanFunction::Value>(p0.size(), BooleanFunction::Value::ZERO);
508 std::vector<BooleanFunction::Value> result(p0.size(), BooleanFunction::Value::ZERO);
511 for (
auto i = p1; i < p0.size(); i++)
513 result[i] = p0[i - p1];
526 std::vector<BooleanFunction::Value>
Lshr(
const std::vector<BooleanFunction::Value>& p0,
const u16 p1)
531 return std::vector<BooleanFunction::Value>(p0.size(), BooleanFunction::Value::ZERO);
534 std::vector<BooleanFunction::Value> result(p0.size(), BooleanFunction::Value::ZERO);
537 for (
auto i = 0u; i < p0.size() - p1; i++)
539 result[i] = p0[i + p1];
552 std::vector<BooleanFunction::Value>
Ashr(
const std::vector<BooleanFunction::Value>& p0,
const u16 p1)
554 auto sign_bit = p0.back();
559 return std::vector<BooleanFunction::Value>(p0.size(), sign_bit);
562 std::vector<BooleanFunction::Value> result(p0.size(), sign_bit);
565 for (
auto i = 0u; i < p0.size() - p1; i++)
567 result[i] = p0[i + p1];
580 std::vector<BooleanFunction::Value>
Rol(
const std::vector<BooleanFunction::Value>& p0,
const u16 p1)
582 auto rotate_amount = p1 % p0.size();
584 if (rotate_amount == 0)
589 std::vector<BooleanFunction::Value> result(p0.size());
592 for (
auto i = 0u; i < p0.size(); i++)
594 auto new_pos = (i + rotate_amount) % p0.size();
595 result[new_pos] = p0[i];
608 std::vector<BooleanFunction::Value>
Ror(
const std::vector<BooleanFunction::Value>& p0,
const u16 p1)
610 auto rotate_amount = p1 % p0.size();
612 if (rotate_amount == 0)
617 std::vector<BooleanFunction::Value> result(p0.size());
620 for (
auto i = 0u; i < p0.size(); i++)
622 auto new_pos = (i + p0.size() - rotate_amount) % p0.size();
623 result[new_pos] = p0[i];
635 std::vector<BooleanFunction::Value>
Sle(
const std::vector<BooleanFunction::Value>& p0,
const std::vector<BooleanFunction::Value>& p1)
637 if (std::any_of(p0.begin(), p0.end(), [](
auto val) { return val == BooleanFunction::Value::X || val == BooleanFunction::Value::Z; })
638 || std::any_of(p1.begin(), p1.end(), [](
auto val) { return val == BooleanFunction::Value::X || val == BooleanFunction::Value::Z; }))
640 return {BooleanFunction::Value::X};
643 auto msb_p0 = p0.back();
644 auto msb_p1 = p1.back();
645 if (msb_p0 == BooleanFunction::Value::ONE && msb_p1 == BooleanFunction::Value::ZERO)
647 return std::vector<BooleanFunction::Value>({BooleanFunction::Value::ONE});
649 else if (msb_p0 == BooleanFunction::Value::ZERO && msb_p1 == BooleanFunction::Value::ONE)
651 return std::vector<BooleanFunction::Value>({BooleanFunction::Value::ZERO});
654 std::vector<BooleanFunction::Value> simplified;
658 for (
auto i = 0u; i < p0.size(); i++)
660 res = p0[i] + !(p1[i]) +
carry;
675 std::vector<BooleanFunction::Value>
Slt(
const std::vector<BooleanFunction::Value>& p0,
const std::vector<BooleanFunction::Value>& p1)
677 if (std::any_of(p0.begin(), p0.end(), [](
auto val) { return val == BooleanFunction::Value::X || val == BooleanFunction::Value::Z; })
678 || std::any_of(p1.begin(), p1.end(), [](
auto val) { return val == BooleanFunction::Value::X || val == BooleanFunction::Value::Z; }))
680 return {BooleanFunction::Value::X};
683 auto msb_p0 = p0.back();
684 auto msb_p1 = p1.back();
685 if (msb_p0 == BooleanFunction::Value::ONE && msb_p1 == BooleanFunction::Value::ZERO)
687 return std::vector<BooleanFunction::Value>({BooleanFunction::Value::ONE});
689 else if (msb_p0 == BooleanFunction::Value::ZERO && msb_p1 == BooleanFunction::Value::ONE)
691 return std::vector<BooleanFunction::Value>({BooleanFunction::Value::ZERO});
694 std::vector<BooleanFunction::Value> simplified;
697 for (
auto i = 0u; i < p0.size(); i++)
699 res = p0[i] + !(p1[i]) +
carry;
700 carry = (res >> 1) & 1;
713 std::vector<BooleanFunction::Value>
Ule(
const std::vector<BooleanFunction::Value>& p0,
const std::vector<BooleanFunction::Value>& p1)
715 if (std::any_of(p0.begin(), p0.end(), [](
auto val) { return val == BooleanFunction::Value::X || val == BooleanFunction::Value::Z; })
716 || std::any_of(p1.begin(), p1.end(), [](
auto val) { return val == BooleanFunction::Value::X || val == BooleanFunction::Value::Z; }))
718 return {BooleanFunction::Value::X};
721 for (
i32 i = p0.size() - 1; i >= 0; i--)
723 if (p0[i] == BooleanFunction::Value::ONE && p1[i] == BooleanFunction::Value::ZERO)
725 return std::vector<BooleanFunction::Value>({BooleanFunction::Value::ZERO});
727 else if (p0[i] == BooleanFunction::Value::ZERO && p1[i] == BooleanFunction::Value::ONE)
729 return std::vector<BooleanFunction::Value>({BooleanFunction::Value::ONE});
732 return std::vector<BooleanFunction::Value>({BooleanFunction::Value::ONE});
742 std::vector<BooleanFunction::Value>
Ult(
const std::vector<BooleanFunction::Value>& p0,
const std::vector<BooleanFunction::Value>& p1)
744 if (std::any_of(p0.begin(), p0.end(), [](
auto val) { return val == BooleanFunction::Value::X || val == BooleanFunction::Value::Z; })
745 || std::any_of(p1.begin(), p1.end(), [](
auto val) { return val == BooleanFunction::Value::X || val == BooleanFunction::Value::Z; }))
747 return {BooleanFunction::Value::X};
750 for (
i32 i = p0.size() - 1; i >= 0; i--)
752 if (p0[i] == BooleanFunction::Value::ONE && p1[i] == BooleanFunction::Value::ZERO)
754 return std::vector<BooleanFunction::Value>({BooleanFunction::Value::ZERO});
756 else if (p0[i] == BooleanFunction::Value::ZERO && p1[i] == BooleanFunction::Value::ONE)
758 return std::vector<BooleanFunction::Value>({BooleanFunction::Value::ONE});
761 return std::vector<BooleanFunction::Value>({BooleanFunction::Value::ZERO});
772 std::vector<BooleanFunction::Value>
Ite(
const std::vector<BooleanFunction::Value>& p0,
const std::vector<BooleanFunction::Value>& p1,
const std::vector<BooleanFunction::Value>& p2)
774 if (p0.front() == BooleanFunction::Value::ONE)
778 else if (p0.front() == BooleanFunction::Value::ZERO)
784 return std::vector<BooleanFunction::Value>(p0.size(), BooleanFunction::Value::X);
801 std::vector<std::vector<BooleanFunction::Value>>& values,
802 const std::vector<u16>& indices)
833 values[1].insert(values[1].end(), values[0].begin(), values[0].end());
834 return OK((values[1]));
837 auto start = indices[0];
838 auto end = indices[1];
839 return OK((std::vector<BooleanFunction::Value>(values[0].begin() + start, values[0].begin() + end + 1)));
842 values[0].resize(node.
size, BooleanFunction::Value::ZERO);
843 return OK((values[0]));
847 return OK((values[0]));
875 return ERR(
"could not propagate constants: not implemented for given node type");
899 std::optional<std::vector<BooleanFunction::Value>> SymbolicExecution::evaluate_constant(
const BooleanFunction&
function)
const
906 std::vector<std::vector<BooleanFunction::Value>> values;
907 std::vector<u16> indices;
911 std::vector<std::vector<BooleanFunction::Value>> operands;
912 std::vector<u16> operand_indices;
914 for (
const auto& node :
function.get_nodes())
916 if (node.is_constant())
918 values.push_back(node.constant);
924 indices.push_back(node.index);
928 if (node.is_variable())
930 const auto it = bindings.find(node.variable);
931 if ((it == bindings.end()) || !it->second->is_constant() || (it->second->size() != node.size))
935 values.push_back(it->second->get_top_level_node().constant);
941 const auto arity = node.get_arity();
949 const auto value_arity = arity - index_arity;
951 if (values.size() < value_arity || indices.size() < index_arity)
956 operands.assign(std::make_move_iterator(values.end() - value_arity), std::make_move_iterator(values.end()));
957 values.erase(values.end() - value_arity, values.end());
958 operand_indices.assign(indices.end() - index_arity, indices.end());
959 indices.erase(indices.end() - index_arity, indices.end());
962 if (folded.is_error())
966 values.push_back(folded.get());
969 if ((values.size() != 1) || !indices.empty())
973 return values.front();
983 if (
auto folded = this->evaluate_constant(
function); folded.has_value())
988 std::vector<BooleanFunction> stack;
989 for (
const auto& node :
function.get_nodes())
991 std::vector<BooleanFunction> parameters;
992 std::move(stack.end() -
static_cast<i64>(node.get_arity()), stack.end(), std::back_inserter(parameters));
993 stack.erase(stack.end() -
static_cast<i64>(node.get_arity()), stack.end());
995 if (
auto simplified = this->simplify(node, std::move(parameters)); simplified.is_ok())
997 stack.emplace_back(simplified.get());
1001 return ERR_APPEND(simplified.get_error(),
"could not evaluate Boolean function within symbolic state: simplification failed");
1005 switch (stack.size())
1008 return OK(stack.back());
1010 return ERR(
"could not evaluate Boolean function within symbolic state: stack is imbalanced");
1020 this->state.set(assignment->second.clone(), std::move(rhs));
1025 return ERR_APPEND(res.get_error(),
"could not to evaluate assignment constraint within the symbolic state: evaluation failed");
1034 const auto&
function = constraint.get_function().get();
1035 auto node_type =
function->get_top_level_node().type;
1039 return ERR(
"invalid node type in function '" + function->to_string() +
"'");
1041 if (
auto res = this->evaluate(*
function); res.is_error())
1043 return ERR_APPEND(res.get_error(),
"could not to evaluate function constraint within the symbolic state: evaluation failed");
1052 std::vector<BooleanFunction> SymbolicExecution::normalize(std::vector<BooleanFunction>&& p)
1054 if (p.size() <= 1ul)
1056 return std::move(p);
1059 std::sort(p.begin(), p.end(), [](
const auto& lhs,
const auto& rhs) {
1060 if (lhs.get_top_level_node().type == rhs.get_top_level_node().type)
1064 return rhs.is_constant();
1066 return std::move(p);
1074 bool is_x_not_y(
const BooleanFunction&
x,
const BooleanFunction&
y)
1076 const BooleanFunction& smaller = (
x.get_nodes().size() <
y.get_nodes().size()) ?
x :
y;
1077 const BooleanFunction& bigger = (
x.get_nodes().size() <
y.get_nodes().size()) ?
y :
x;
1080 if (smaller.get_nodes().size() != (bigger.get_nodes().size() - 1))
1092 for (
u32 idx = 0; idx < smaller.get_nodes().size(); idx++)
1094 if (smaller.get_nodes().at(idx) != bigger.get_nodes().at(idx))
1104 Result<BooleanFunction> SymbolicExecution::simplify(
const BooleanFunction::Node& node, std::vector<BooleanFunction>&& p)
const
1106 if (!p.empty() && std::all_of(p.begin(), p.end(), [](
const auto&
function) { return function.is_constant() || function.is_index(); }))
1110 return ERR_APPEND(res.get_error(),
"could not simplify sub-expression in abstract syntax tree: constant propagation failed");
1118 if (node.is_commutative())
1120 p = SymbolicExecution::normalize(std::move(p));
1131 case BooleanFunction::NodeType::Constant: {
1132 return OK(BooleanFunction::Const(node.constant));
1134 case BooleanFunction::NodeType::Index: {
1135 return OK(BooleanFunction::Index(node.index, node.size));
1137 case BooleanFunction::NodeType::Variable: {
1138 return OK(this->
state.get(BooleanFunction::Var(node.variable, node.size)));
1144 return OK(BooleanFunction::Const(0, node.size));
1147 if (p[1] == One(node.size))
1157 if (is_x_not_y(p[0], p[1]))
1159 return OK(BooleanFunction::Const(0, node.size));
1164 auto p0_parameter = p[0].get_parameters();
1165 auto p1_parameter = p[1].get_parameters();
1168 if (p0_parameter[0] == p1_parameter[0])
1170 return OK(p0_parameter[0] | (p0_parameter[1] & p1_parameter[1]));
1173 if (p0_parameter[0] == p1_parameter[1])
1175 return OK(p0_parameter[0] | (p0_parameter[1] & p1_parameter[0]));
1179 if (p0_parameter[1] == p1_parameter[0])
1181 return OK(p0_parameter[1] | (p0_parameter[0] & p1_parameter[1]));
1184 if (p0_parameter[1] == p1_parameter[1])
1186 return OK(p0_parameter[1] | (p0_parameter[0] & p1_parameter[0]));
1192 auto p1_parameter = p[1].get_parameters();
1194 if (p[0] == p1_parameter[1])
1199 if (p[0] == p1_parameter[0])
1205 if (is_x_not_y(p1_parameter[0], p[0]))
1207 return OK(BooleanFunction::Const(0, node.size));
1210 if (is_x_not_y(p1_parameter[1], p[0]))
1212 return OK(BooleanFunction::Const(0, node.size));
1218 auto p1_parameter = p[1].get_parameters();
1221 if (p1_parameter[0] == p[0])
1226 if (p1_parameter[1] == p[0])
1231 if (is_x_not_y(p1_parameter[0], p[0]))
1236 if (is_x_not_y(p1_parameter[1], p[0]))
1244 auto p0_parameter = p[0].get_parameters();
1247 if (p0_parameter[0] == p[1])
1253 if (p0_parameter[1] == p[1])
1258 if (is_x_not_y(p0_parameter[0], p[1]))
1260 return OK(BooleanFunction::Const(0, node.size));
1263 if (is_x_not_y(p0_parameter[1], p[1]))
1265 return OK(BooleanFunction::Const(0, node.size));
1271 auto p0_parameter = p[0].get_parameters();
1274 if (p0_parameter[0] == p[1])
1279 if (p0_parameter[1] == p[1])
1284 if (is_x_not_y(p0_parameter[0], p[1]))
1289 if (is_x_not_y(p0_parameter[1], p[1]))
1295 return OK(p[0] & p[1]);
1301 return OK(p[0].get_parameters()[0]);
1307 auto p0_parameter = p[0].get_parameters();
1310 return BooleanFunction::Or(p0_parameter[0].get_parameters()[0].clone(), p0_parameter[1].get_parameters()[0].clone(), node.size);
1317 auto p0_parameter = p[0].get_parameters();
1320 return BooleanFunction::And(p0_parameter[0].get_parameters()[0].clone(), p0_parameter[1].get_parameters()[0].clone(), node.size);
1327 auto p0_parameter = p[0].get_parameters();
1328 return OK((~p0_parameter[0]) & (~p0_parameter[1]));
1334 auto p0_parameter = p[0].get_parameters();
1335 return OK((~p0_parameter[0]) | (~p0_parameter[1]));
1349 if (p[1] == One(node.size))
1361 if (is_x_not_y(p[0], p[1]))
1363 return OK(One(node.size));
1368 auto p0_parameter = p[0].get_parameters();
1369 auto p1_parameter = p[1].get_parameters();
1372 if (p0_parameter[0] == p1_parameter[0])
1374 return OK(p0_parameter[0] & (p0_parameter[1] | p1_parameter[1]));
1377 if (p0_parameter[0] == p1_parameter[1])
1379 return OK(p0_parameter[0] & (p0_parameter[1] | p1_parameter[0]));
1382 if (p0_parameter[1] == p1_parameter[0])
1384 return OK(p0_parameter[1] & (p0_parameter[0] | p1_parameter[1]));
1387 if (p0_parameter[1] == p1_parameter[1])
1389 return OK(p0_parameter[1] & (p0_parameter[0] | p1_parameter[0]));
1395 auto p1_parameter = p[1].get_parameters();
1397 if (is_x_not_y(p1_parameter[1], p[0]))
1403 if ((p1_parameter[0] == p[0]) || (p1_parameter[1] == p[0]))
1409 if (is_x_not_y(p1_parameter[0], p[0]))
1414 if (is_x_not_y(p1_parameter[1], p[0]))
1422 auto p1_parameter = p[1].get_parameters();
1425 if (p1_parameter[0] == p[0])
1430 if (p1_parameter[1] == p[0])
1436 if (is_x_not_y(p1_parameter[0], p[0]))
1438 return OK(One(node.size));
1442 if (is_x_not_y(p1_parameter[1], p[0]))
1444 return OK(One(node.size));
1450 auto p0_parameter = p[0].get_parameters();
1453 if (p0_parameter[0] == p[1])
1458 if (p0_parameter[1] == p[1])
1464 if (is_x_not_y(p0_parameter[0], p[1]))
1466 return OK(One(node.size));
1470 if (is_x_not_y(p0_parameter[1], p[1]))
1472 return OK(One(node.size));
1478 auto p0_parameter = p[0].get_parameters();
1481 if (p0_parameter[0] == p[1])
1486 if (p0_parameter[1] == p[1])
1492 if (is_x_not_y(p0_parameter[0], p[1]))
1498 if (is_x_not_y(p0_parameter[1], p[1]))
1513 if (p[1] == One(node.size))
1520 return OK(BooleanFunction::Const(0, node.size));
1523 if (is_x_not_y(p[0], p[1]))
1525 return OK(One(node.size));
1548 return OK(BooleanFunction::Const(0, node.size));
1557 return OK(BooleanFunction::Const(0, node.size));
1576 return OK(BooleanFunction::Const(1, node.size));
1590 return OK(BooleanFunction::Const(1, node.size));
1599 return OK(BooleanFunction::Const(0, node.size));
1604 return OK(BooleanFunction::Const(0, node.size));
1613 return OK(BooleanFunction::Const(0, node.size));
1618 return OK(BooleanFunction::Const(0, node.size));
1623 case BooleanFunction::NodeType::Slice: {
1631 if (node.size == p[0].size() && p[1].has_index_value(0) && p[2].has_index_value(node.size - 1))
1636 if (
const auto start_res = p[1].get_index_value(), end_res = p[2].get_index_value(); start_res.is_ok() && end_res.is_ok())
1638 const auto start = start_res.get(), end = end_res.get();
1641 if (p[0].is(BooleanFunction::NodeType::Slice))
1643 const auto inner = p[0].get_parameters();
1644 if (
const auto inner_start = inner[1].get_index_value(); inner_start.is_ok())
1646 const auto offset = inner_start.get();
1647 return BooleanFunction::Slice(inner[0].clone(),
1648 BooleanFunction::Index(offset + start, inner[0].
size()),
1649 BooleanFunction::Index(offset + end, inner[0].
size()),
1655 if (p[0].is(BooleanFunction::NodeType::Zext) || p[0].is(BooleanFunction::NodeType::Sext))
1657 const auto extended = p[0].get_parameters();
1658 const auto original = extended[0].size();
1661 if (p[0].is(BooleanFunction::NodeType::Zext) && (start >= original))
1663 return OK(BooleanFunction::Const(0, node.size));
1669 return BooleanFunction::Slice(extended[0].clone(), BooleanFunction::Index(start, original), BooleanFunction::Index(end, original), node.size);
1675 if (p[0].is(BooleanFunction::NodeType::Concat))
1677 const auto halves = p[0].get_parameters();
1678 const auto lower = halves[1].size();
1683 return BooleanFunction::Slice(halves[1].clone(), BooleanFunction::Index(start, lower), BooleanFunction::Index(end, lower), node.size);
1688 return BooleanFunction::Slice(halves[0].clone(),
1689 BooleanFunction::Index(start - lower, halves[0].
size()),
1690 BooleanFunction::Index(end - lower, halves[0].
size()),
1696 return BooleanFunction::Slice(p[0].clone(), p[1].clone(), p[2].clone(), node.size);
1698 case BooleanFunction::NodeType::Concat: {
1700 if (p[0].is_constant() && p[1].is_constant())
1702 if ((p[0].
size() + p[1].
size()) <= 64)
1704 return OK(BooleanFunction::Const((p[0].get_constant_value_u64().get() << p[1].
size()) + p[1].get_constant_value_u64().get(), p[0].
size() + p[1].
size()));
1709 if (p[0].is(BooleanFunction::NodeType::Slice) && p[1].is(BooleanFunction::NodeType::Concat))
1711 auto p1_parameter = p[1].get_parameters();
1713 if (p1_parameter[0].is(BooleanFunction::NodeType::Slice))
1715 auto p0_parameter = p[0].get_parameters();
1716 auto p10_parameter = p1_parameter[0].get_parameters();
1718 if (p0_parameter[0] == p10_parameter[0])
1720 if (p1_parameter[1].is(BooleanFunction::NodeType::Slice))
1722 auto p11_parameter = p1_parameter[1].get_parameters();
1725 if (p11_parameter[0] != p10_parameter[0])
1727 if (
auto concatination = BooleanFunction::Concat(p[0].clone(), p1_parameter[0].clone(), p[0].
size() + p1_parameter[0].
size()); concatination.is_ok())
1729 return BooleanFunction::Concat(concatination.get(), p1_parameter[1].clone(), concatination.get().size() + p1_parameter[1].size());
1733 else if (p1_parameter[1].is(BooleanFunction::NodeType::Concat))
1735 auto p11_parameter = p1_parameter[1].get_parameters();
1737 if (p11_parameter[0].is(BooleanFunction::NodeType::Slice))
1739 auto p110_parameter = p11_parameter[0].get_parameters();
1742 if (p110_parameter[0] != p10_parameter[0])
1744 auto c1 = BooleanFunction::Concat(p[0].clone(), p1_parameter[0].clone(), p[0].
size() + p1_parameter[0].
size());
1746 return BooleanFunction::Concat(c1.get().clone(), p1_parameter[1].clone(), c1.get().size() + p1_parameter[1].size());
1753 if (
auto concatination = BooleanFunction::Concat(p[0].clone(), p1_parameter[0].clone(), p[0].
size() + p1_parameter[0].
size()); concatination.is_ok())
1755 return BooleanFunction::Concat(concatination.get(), p1_parameter[1].clone(), concatination.get().size() + p1_parameter[1].size());
1762 if (p[0].is(BooleanFunction::NodeType::Slice) && p[1].is(BooleanFunction::NodeType::Slice))
1764 auto p0_parameter = p[0].get_parameters();
1765 auto p1_parameter = p[1].get_parameters();
1767 if (p0_parameter[0] == p1_parameter[0])
1770 if ((p1_parameter[2].get_index_value().get() == (p0_parameter[1].get_index_value().get() - 1)))
1772 return BooleanFunction::Slice(p0_parameter[0].clone(), p1_parameter[1].clone(), p0_parameter[2].clone(), p[0].
size() + p[1].
size());
1776 if ((p1_parameter[2].get_index_value().get() == p0_parameter[1].get_index_value().get())
1777 && (p1_parameter[2].get_index_value().get() == p0_parameter[2].get_index_value().get()))
1779 return BooleanFunction::Sext(p[1].clone(), BooleanFunction::Index(p[1].
size() + 1, p[1].
size() + 1), p[1].
size() + 1);
1785 if (p[0].is(BooleanFunction::NodeType::Slice) && p[1].is(BooleanFunction::NodeType::Sext))
1787 auto p1_parameter = p[1].get_parameters();
1789 if (p1_parameter[0].is(BooleanFunction::NodeType::Slice))
1791 auto p0_parameter = p[0].get_parameters();
1792 auto p10_parameter = p1_parameter[0].get_parameters();
1794 if ((p0_parameter[0] == p10_parameter[0]) && (p0_parameter[1] == p0_parameter[2]) && (p0_parameter[1].get_index_value().get() == p10_parameter[2].get_index_value().get()))
1796 return BooleanFunction::Sext(p1_parameter[0].clone(), BooleanFunction::Index(p[1].
size() + 1, p[1].
size() + 1), p[1].
size() + 1);
1802 if (p[0].is(BooleanFunction::NodeType::Slice) && p[1].is(BooleanFunction::NodeType::Concat))
1804 auto p1_parameter = p[1].get_parameters();
1806 if (p1_parameter[0].is(BooleanFunction::NodeType::Sext))
1808 auto p10_parameter = p1_parameter[0].get_parameters();
1810 if (p10_parameter[0].is(BooleanFunction::NodeType::Slice))
1812 auto p0_parameter = p[0].get_parameters();
1813 auto p100_parameter = p10_parameter[0].get_parameters();
1815 if ((p0_parameter[0] == p100_parameter[0]) && (p0_parameter[1] == p0_parameter[2])
1816 && (p0_parameter[1].get_index_value().get() == p100_parameter[2].get_index_value().get()))
1818 if (
auto extension =
1819 BooleanFunction::Sext(p10_parameter[0].clone(), BooleanFunction::Index(p1_parameter[0].
size() + 1, p1_parameter[0].
size() + 1), p1_parameter[0].
size() + 1);
1822 return BooleanFunction::Concat(extension.get(), p1_parameter[1].clone(), extension.get().size() + p1_parameter[1].size());
1829 return BooleanFunction::Concat(p[0].clone(), p[1].clone(), node.size);
1831 case BooleanFunction::NodeType::Zext: {
1833 if (node.size == p[0].size())
1838 if (p[0].is(BooleanFunction::NodeType::Zext))
1840 const auto inner = p[0].get_parameters();
1841 return BooleanFunction::Zext(inner[0].clone(), BooleanFunction::Index(node.size, node.size), node.size);
1844 return BooleanFunction::Zext(p[0].clone(), p[1].clone(), node.size);
1846 case BooleanFunction::NodeType::Sext: {
1848 if (node.size == p[0].size())
1853 if (p[0].is(BooleanFunction::NodeType::Sext))
1855 const auto inner = p[0].get_parameters();
1856 return BooleanFunction::Sext(inner[0].clone(), BooleanFunction::Index(node.size, node.size), node.size);
1859 return BooleanFunction::Sext(p[0].clone(), p[1].clone(), node.size);
1865 return OK(BooleanFunction::Const(1, node.size));
1868 if (is_x_not_y(p[0], p[1]))
1870 return OK(BooleanFunction::Const(0, node.size));
1873 if (p[0].
size() == 1)
1893 return OK(BooleanFunction::Const(1, node.size));
1902 return OK(BooleanFunction::Const(0, node.size));
1911 return OK(BooleanFunction::Const(1, node.size));
1916 return OK(BooleanFunction::Const(1, node.size));
1919 if (p[1] == One(p[1].
size()))
1921 return OK(BooleanFunction::Const(1, node.size));
1930 return OK(BooleanFunction::Const(0, node.size));
1935 return OK(BooleanFunction::Const(0, node.size));
1938 if (p[0] == One(p[0].
size()))
1940 return OK(BooleanFunction::Const(0, node.size));
1979 return ERR(
"could not simplify sub-expression in abstract syntax tree: not implemented for given node type");
1985 if (node.get_arity() != p.size())
1987 return ERR(
"could not propagate constants: arity does not match number of parameters");
1990 std::vector<std::vector<BooleanFunction::Value>> values;
1991 std::vector<u16> indices;
1992 values.reserve(p.size());
1994 for (
const auto& parameter : p)
1996 if (parameter.is_index())
1998 indices.push_back(parameter.get_index_value().get());
2003 values.emplace_back(parameter.get_top_level_node().constant);
2009 return OK(BooleanFunction::Const(res.get()));
2013 return ERR(res.get_error());
Value
represents the type of the node
static BooleanFunction Const(const BooleanFunction::Value &value)
static Result< u64 > to_u64(const std::vector< BooleanFunction::Value > &value)
SymbolicExecution(const std::vector< BooleanFunction > &variables={})
Result< BooleanFunction > evaluate(const BooleanFunction &function) const
SymbolicState state
The current symbolic state.
std::unordered_map< std::string, const BooleanFunction * > get_bindings() const
#define ERR_APPEND(prev_error, message)
Result< BooleanFunction > constant_propagation(const BooleanFunction::Node &node, std::vector< BooleanFunction > &&p)
std::vector< BooleanFunction::Value > Sle(const std::vector< BooleanFunction::Value > &p0, const std::vector< BooleanFunction::Value > &p1)
std::vector< BooleanFunction::Value > Sdiv(const std::vector< BooleanFunction::Value > &p0, const std::vector< BooleanFunction::Value > &p1)
std::vector< BooleanFunction::Value > Ite(const std::vector< BooleanFunction::Value > &p0, const std::vector< BooleanFunction::Value > &p1, const std::vector< BooleanFunction::Value > &p2)
std::vector< BooleanFunction::Value > Xor(const std::vector< BooleanFunction::Value > &p0, const std::vector< BooleanFunction::Value > &p1)
std::vector< BooleanFunction::Value > Ashr(const std::vector< BooleanFunction::Value > &p0, const u16 p1)
std::vector< BooleanFunction::Value > Ror(const std::vector< BooleanFunction::Value > &p0, const u16 p1)
Result< std::vector< BooleanFunction::Value > > fold(const BooleanFunction::Node &node, std::vector< std::vector< BooleanFunction::Value >> &values, const std::vector< u16 > &indices)
std::vector< BooleanFunction::Value > Srem(const std::vector< BooleanFunction::Value > &p0, const std::vector< BooleanFunction::Value > &p1)
std::vector< BooleanFunction::Value > Urem(const std::vector< BooleanFunction::Value > &p0, const std::vector< BooleanFunction::Value > &p1)
std::vector< BooleanFunction::Value > Ule(const std::vector< BooleanFunction::Value > &p0, const std::vector< BooleanFunction::Value > &p1)
std::vector< BooleanFunction::Value > Sub(const std::vector< BooleanFunction::Value > &p0, const std::vector< BooleanFunction::Value > &p1)
std::vector< BooleanFunction::Value > Add(const std::vector< BooleanFunction::Value > &p0, const std::vector< BooleanFunction::Value > &p1)
std::vector< BooleanFunction::Value > Or(const std::vector< BooleanFunction::Value > &p0, const std::vector< BooleanFunction::Value > &p1)
std::vector< BooleanFunction::Value > Not(const std::vector< BooleanFunction::Value > &p)
std::vector< BooleanFunction::Value > Rol(const std::vector< BooleanFunction::Value > &p0, const u16 p1)
std::vector< BooleanFunction::Value > Mul(const std::vector< BooleanFunction::Value > &p0, const std::vector< BooleanFunction::Value > &p1)
std::vector< BooleanFunction::Value > And(const std::vector< BooleanFunction::Value > &p0, const std::vector< BooleanFunction::Value > &p1)
std::vector< BooleanFunction::Value > Shl(const std::vector< BooleanFunction::Value > &p0, const u16 p1)
std::vector< BooleanFunction::Value > Udiv(const std::vector< BooleanFunction::Value > &p0, const std::vector< BooleanFunction::Value > &p1)
std::vector< BooleanFunction::Value > Slt(const std::vector< BooleanFunction::Value > &p0, const std::vector< BooleanFunction::Value > &p1)
std::vector< BooleanFunction::Value > Ult(const std::vector< BooleanFunction::Value > &p0, const std::vector< BooleanFunction::Value > &p1)
std::vector< BooleanFunction::Value > Eq(const std::vector< BooleanFunction::Value > &p0, const std::vector< BooleanFunction::Value > &p1)
std::vector< BooleanFunction::Value > Lshr(const std::vector< BooleanFunction::Value > &p0, const u16 p1)
bool has_constant_value(const z3::expr &e, const u64 &val)
u16 type
The type of the node.
u16 size
The bit-size of the node.
static constexpr u16 Srem
static constexpr u16 Udiv
static constexpr u16 Sdiv
static constexpr u16 Urem
static constexpr u16 Lshr
static constexpr u16 Sext
static constexpr u16 Ashr
static constexpr u16 Concat
static constexpr u16 Slice
static constexpr u16 Zext
bool is_assignment() const
Result< const std::pair< BooleanFunction, BooleanFunction > * > get_assignment() const