23 auto reduce_to_z3 = [&ctx, &var2expr](
const auto& node,
auto&& p) -> std::tuple<bool, z3::expr> {
24 if (node.get_arity() != p.size())
26 return {
false, z3::expr(ctx)};
32 return {
true, ctx.bv_val(node.index, node.size)};
35 for (
u32 i = 0; i < node.constant.size(); i++)
37 if (node.constant.at(i) == BooleanFunction::Value::ONE)
41 else if (node.constant.at(i) == BooleanFunction::Value::ZERO)
47 return {
false, z3::expr(ctx)};
51 return {
true, ctx.bv_val(bits.size(),
reinterpret_cast<bool*
>(bits.data()))};
54 if (
auto it = var2expr.find(node.variable); it != var2expr.end())
56 return {
true, it->second};
58 return {
true, ctx.bv_const(node.variable.c_str(), node.size)};
62 return {
true, p[0] & p[1]};
64 return {
true, p[0] | p[1]};
68 return {
true, p[0] ^ p[1]};
70 return {
true, p[0] + p[1]};
72 return {
true, p[0] - p[1]};
74 return {
true, p[0] * p[1]};
76 return {
true, p[0] / p[1]};
78 return {
true, z3::udiv(p[0], p[1])};
80 return {
true, z3::srem(p[0], p[1])};
82 return {
true, z3::urem(p[0], p[1])};
84 return {
true, z3::concat(p[0], p[1])};
86 return {
true, p[0].extract(p[2].get_numeral_uint(), p[1].get_numeral_uint())};
88 return {
true, z3::zext(p[0], p[1].get_numeral_uint() - p[0].get_sort().bv_size())};
90 return {
true, z3::sext(p[0], p[1].get_numeral_uint() - p[0].get_sort().bv_size())};
92 return {
true, z3::shl(p[0], p[1])};
94 return {
true, z3::lshr(p[0], p[1])};
96 return {
true, z3::ashr(p[0], p[1])};
98 return {
true, p[0].rotate_left(p[1].get_numeral_uint())};
100 return {
true, p[0].rotate_right(p[1].get_numeral_uint())};
102 return {
true, p[0] == p[1]};
104 return {
true, z3::sle(p[0], p[1])};
106 return {
true, z3::slt(p[0], p[1])};
108 return {
true, z3::ule(p[0], p[1])};
110 return {
true, z3::ult(p[0], p[1])};
112 return {
true, z3::ite(p[0], p[1], p[2])};
114 log_error(
"netlist",
"Not implemented reached for nodetype {} in z3 conversion", node.type);
115 return {
false, z3::expr(ctx)};
119 std::vector<z3::expr> stack;
122 std::vector<z3::expr> operands;
123 std::move(stack.end() -
static_cast<i64>(node.get_arity()), stack.end(), std::back_inserter(operands));
124 stack.erase(stack.end() -
static_cast<i64>(node.get_arity()), stack.end());
126 if (
auto [ok, reduction] = reduce_to_z3(node, std::move(operands)); ok)
128 stack.emplace_back(reduction);
132 return z3::expr(ctx);
136 switch (stack.size())
141 return z3::expr(ctx);
147 std::vector<u8> bits;
148 for (
u32 i = 0; i < bit_string.length(); i++)
150 if (bit_string.at(i) ==
'1')
154 else if (bit_string.at(i) ==
'0')
160 return ERR(
"cannot generate value from binary string: encountered unexpected character " + bit_string.at(i));
164 return OK(ctx.bv_val(bits.size(),
reinterpret_cast<bool*
>(bits.data())));
174 size = e.get_sort().bv_size();
184 std::vector<BooleanFunction::Value> boolean_values;
185 const std::string val_str = Z3_get_numeral_binary_string(e.ctx(), e);
186 for (
u32 idx = 0; idx < val_str.size(); idx++)
188 if (val_str.at(idx) ==
'1')
190 boolean_values.push_back(BooleanFunction::Value::ONE);
192 else if (val_str.at(idx) ==
'0')
194 boolean_values.push_back(BooleanFunction::Value::ZERO);
198 return ERR(
"cannot convert expression to boolean function: failed to translate character " + std::to_string(val_str.at(idx)) +
" to Boolean value.");
205 else if (e.is_const())
208 const std::string
name = e.decl().name().str();
213 const std::string
name = e.decl().name().str();
223 const auto op = e.decl().decl_kind();
224 auto num_args = e.num_args();
225 std::vector<BooleanFunction> args;
227 for (
u32 i = 0; i < e.num_args(); i++)
229 const auto arg = e.arg(i);
230 if (
const auto res = to_bf_internal(arg, cache); res.is_ok())
234 args.push_back(res.get());
238 return ERR(res.get_error());
246 for (
u64 i = 2; i < num_args; i++)
249 bf_res.map<BooleanFunction>([arg = std::move(args.at(i)),
size](BooleanFunction&& bf)
mutable {
return BooleanFunction::And(std::move(bf), std::move(arg),
size); });
255 for (
u64 i = 2; i < num_args; i++)
258 bf_res.map<BooleanFunction>([arg = std::move(args.at(i)),
size](BooleanFunction&& bf)
mutable {
return BooleanFunction::Or(std::move(bf), std::move(arg),
size); });
265 return ERR(
"operation 'NOT' must have arity 1");
271 for (
u64 i = 2; i < num_args; i++)
274 bf_res.map<BooleanFunction>([arg = std::move(args.at(i)),
size](BooleanFunction&& bf)
mutable {
return BooleanFunction::Xor(std::move(bf), std::move(arg),
size); });
281 return ERR(
"operation 'NEG' must have arity 1");
283 return ERR(
"Negation not implemented");
287 for (
u64 i = 2; i < num_args; i++)
290 bf_res.map<BooleanFunction>([arg = std::move(args.at(i)),
size](BooleanFunction&& bf)
mutable {
return BooleanFunction::Add(std::move(bf), std::move(arg),
size); });
296 for (
u64 i = 2; i < num_args; i++)
299 bf_res.map<BooleanFunction>([arg = std::move(args.at(i)),
size](BooleanFunction&& bf)
mutable {
return BooleanFunction::Sub(std::move(bf), std::move(arg),
size); });
305 for (
u64 i = 2; i < num_args; i++)
308 bf_res.map<BooleanFunction>([arg = std::move(args.at(i)),
size](BooleanFunction&& bf)
mutable {
return BooleanFunction::Mul(std::move(bf), std::move(arg),
size); });
315 return ERR(
"operation 'SDIV' must have arity 2");
321 return ERR(
"operation 'UDIV' must have arity 2");
327 return ERR(
"operation 'SREM' must have arity 2");
333 return ERR(
"operation 'UREM' must have arity 2");
337 auto bf_res =
BooleanFunction::Concat(std::move(args.at(0)), std::move(args.at(1)), args.at(0).size() + args.at(1).size());
338 for (
u64 i = 2; i < num_args; i++)
340 bf_res = bf_res.map<BooleanFunction>(
341 [arg = std::move(args.at(i)),
size](BooleanFunction&& bf)
mutable {
return BooleanFunction::Concat(std::move(bf), std::move(arg), bf.size() + arg.size()); });
345 case Z3_OP_EXTRACT: {
348 return ERR(
"operation 'SLICE' must have arity 1");
351 const u32 operand_size = args.at(0).size();
355 case Z3_OP_ZERO_EXT: {
358 return ERR(
"operation 'ZEXT' must have arity 1");
363 case Z3_OP_SIGN_EXT: {
366 return ERR(
"operation 'SEXT' must have arity 1");
374 return ERR(
"operation 'SHL' must have arity 2");
380 return ERR(
"operation 'LSHR' must have arity 2");
386 return ERR(
"operation 'ASHR' must have arity 2");
389 case Z3_OP_ROTATE_LEFT:
392 return ERR(
"operation 'ROL' must have arity 1");
395 case Z3_OP_ROTATE_RIGHT:
398 return ERR(
"operation 'ROR' must have arity 1");
404 return ERR(
"operation 'EQ' must have arity 2");
410 return ERR(
"operation 'SLE' must have arity 2");
416 return ERR(
"operation 'SLT' must have arity 2");
422 return ERR(
"operation 'ULE' must have arity 2");
428 return ERR(
"operation 'ULT' must have arity 2");
434 return ERR(
"operation 'ITE' must have arity 3");
438 return ERR(
"operation '" + e.decl().name().str() +
"' with arity " + std::to_string(num_args) +
" is not yet implemented");
445 std::map<z3::expr, BooleanFunction> cache;
446 return to_bf_internal(e, cache);
451 auto s = z3::solver(e.ctx());
452 if (e.get_sort().is_bv())
454 s.add(e == e.ctx().bv_val(0, e.get_sort().bv_size()));
458 s.add(e == e.ctx().bool_val(
true));
466 const auto c_file = converter.convert_z3_expr_to_func(e);
471 std::string
to_verilog(
const z3::expr& e,
const std::map<std::string, bool>& control_mapping)
474 converter.set_control_mapping(control_mapping);
476 const auto verilog_file = converter.convert_z3_expr_to_func(e);
483 std::set<u32> visited = {e.id()};
484 std::vector<z3::expr> stack = {e};
486 std::set<std::string> var_names;
488 while (!stack.empty())
490 const auto n = stack.back();
498 if (n.is_var() || n.is_const())
500 var_names.insert(n.to_string());
504 for (
u32 i = 0; i < n.num_args(); i++)
506 const auto a_i = n.arg(i);
507 if (visited.find(a_i.id()) == visited.end())
509 visited.insert(a_i.id());
510 stack.push_back(a_i);
527 std::set<u32> net_ids;
529 for (
const auto& var : variable_names)
532 if (id_res.is_error())
534 log_error(
"z3_utils",
"{}", id_res.get_error().get());
536 net_ids.insert(id_res.get());
544 auto expr_vec = ctx.parse_string(
to_smt2(e).c_str());
545 return expr_vec.back().arg(0).simplify();
static Result< BooleanFunction > Slt(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< BooleanFunction > Ite(BooleanFunction &&p0, BooleanFunction &&p1, BooleanFunction &&p2, u16 size)
static Result< BooleanFunction > Eq(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static BooleanFunction Var(const std::string &name, u16 size=1)
static Result< BooleanFunction > Xor(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< BooleanFunction > Add(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< BooleanFunction > Lshr(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< BooleanFunction > Zext(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< BooleanFunction > Mul(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< BooleanFunction > Ule(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< BooleanFunction > Sub(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< BooleanFunction > Sext(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< BooleanFunction > Udiv(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< BooleanFunction > Concat(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< BooleanFunction > Ult(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static BooleanFunction Index(u16 index, u16 size)
static Result< BooleanFunction > Sle(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< BooleanFunction > Slice(BooleanFunction &&p0, BooleanFunction &&p1, BooleanFunction &&p2, u16 size)
const std::vector< BooleanFunction::Node > & get_nodes() const
static Result< BooleanFunction > Or(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< BooleanFunction > Urem(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< BooleanFunction > Ror(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< BooleanFunction > Sdiv(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static BooleanFunction Const(const BooleanFunction::Value &value)
static Result< BooleanFunction > Ashr(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< BooleanFunction > Not(BooleanFunction &&p0, u16 size)
static Result< BooleanFunction > And(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< BooleanFunction > Shl(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< BooleanFunction > Rol(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< BooleanFunction > Srem(BooleanFunction &&p0, BooleanFunction &&p1, u16 size)
static Result< u32 > get_net_id_from(const BooleanFunction &var)
#define log_error(channel,...)
std::set< std::string > get_variable_names(const z3::expr &e)
Extracts all variable names from a z3 expression.
std::set< u32 > extract_net_ids(const z3::expr &e)
Extracts all net IDs from the variables of a z3 expression.
std::string to_smt2(const z3::expr &e)
z3::expr from_bf(const BooleanFunction &bf, z3::context &ctx, const std::map< std::string, z3::expr > &var2expr={})
std::string to_verilog(const z3::expr &e, const std::map< std::string, bool > &control_mapping={})
Translates a z3 expression into a verilog network representation.
std::string to_cpp(const z3::expr &e)
z3::expr get_expr_in_ctx(const z3::expr &e, z3::context &ctx)
Translates the expr to another context.
Result< z3::expr > value_from_binary_string(z3::context &ctx, const std::string &bit_string)
Result< BooleanFunction > to_bf(const z3::expr &e)
static constexpr u16 Constant
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 Index
static constexpr u16 Concat
static constexpr u16 Slice
static constexpr u16 Zext
static constexpr u16 Variable