33
44#include " concrete_rt.hpp"
55#include " symbolic_rt.hpp"
6+ #include " z3++.h"
67#include < array>
8+ #include < set>
9+ #include < string>
10+ #include < tuple>
711#include < vector>
812
913class Solver {
1014public:
11- Solver () : count(0 ) {
12- envs[0 ] = {Num (0 ), Num (0 )};
13- envs[1 ] = {Num (1 ), Num (2 )};
14- }
15- std::optional<std::vector<Num>> solve (const std::vector<SymVal> &conditions) {
16- // here is just a placeholder implementation to simulate solving result
17- if (count >= envs.size ()) {
18- return std::nullopt ; // No more environments to return
15+ Solver () {}
16+ std::optional<std::tuple<std::vector<Num>, std::set<int >>>
17+ solve (const std::vector<SymVal> &conditions) {
18+ // make an conjunction of all conditions
19+ z3::expr conjunction = z3_ctx.bool_val (true );
20+ for (const auto &cond : conditions) {
21+ auto z3_cond = build_z3_expr (cond);
22+ conjunction = conjunction && z3_cond != z3_ctx.bv_val (0 , 32 );
23+ }
24+ #ifdef DEBUG
25+ std::cout << " Symbolic conditions size: " << conditions.size () << std::endl;
26+ std::cout << " Solving conditions: " << conjunction << std::endl;
27+ #endif
28+ // call z3 to solve the condition
29+ z3::solver z3_solver (z3_ctx);
30+ z3_solver.add (conjunction);
31+ switch (z3_solver.check ()) {
32+ case z3::unsat:
33+ return std::nullopt ; // No solution found
34+ case z3::sat: {
35+ z3::model model = z3_solver.get_model ();
36+ std::vector<Num> result (max_id + 1 , Num (0 ));
37+ // Reference:
38+ // https://github.com/Z3Prover/z3/blob/master/examples/c%2B%2B/example.cpp#L59
39+
40+ std::cout << " Solved Z3 model" << model << std::endl;
41+ std::set<int > seen_ids;
42+ for (unsigned i = 0 ; i < model.size (); ++i) {
43+ z3::func_decl var = model[i];
44+ z3::expr value = model.get_const_interp (var);
45+ std::string name = var.name ().str ();
46+ if (name.starts_with (" s_" )) {
47+ int id = std::stoi (name.substr (2 ));
48+ seen_ids.insert (id);
49+ result[id] = Num (value.get_numeral_int ());
50+ } else {
51+ std::cout << " Find a variable that is not created by GenSym: " << name
52+ << std::endl;
53+ }
54+ }
55+ return std::make_tuple (result, seen_ids);
1956 }
20- return envs[count++ % envs.size ()];
57+ case z3::unknown:
58+ throw std::runtime_error (" Z3 solver returned unknown status" );
59+ }
60+ return std::nullopt ; // Should not reach here
2161 }
2262
2363private:
24- std::array<std::vector<Num>, 5 > envs ;
25- int count ;
64+ z3::context z3_ctx ;
65+ z3::expr build_z3_expr ( const SymVal &sym_val) ;
2666};
2767
68+ inline z3::expr Solver::build_z3_expr (const SymVal &sym_val) {
69+ if (auto sym = std::dynamic_pointer_cast<Symbol>(sym_val.symptr )) {
70+ return z3_ctx.bv_const ((" s_" + std::to_string (sym->get_id ())).c_str (), 32 );
71+ } else if (auto concrete =
72+ std::dynamic_pointer_cast<SymConcrete>(sym_val.symptr )) {
73+ return z3_ctx.bv_val (concrete->value .value , 32 );
74+ } else if (auto binary =
75+ std::dynamic_pointer_cast<SymBinary>(sym_val.symptr )) {
76+ auto bit_width = 32 ;
77+ z3::expr zero_bv =
78+ z3_ctx.bv_val (0 , bit_width); // Represents 0 as a 32-bit bitvector
79+ z3::expr one_bv =
80+ z3_ctx.bv_val (1 , bit_width); // Represents 1 as a 32-bit bitvector
81+
82+ z3::expr left = build_z3_expr (binary->lhs );
83+ z3::expr right = build_z3_expr (binary->rhs );
84+ // TODO: make sure the semantics of these operations are aligned with wasm
85+ switch (binary->op ) {
86+ case EQ: {
87+ auto temp_bool = left == right;
88+ return z3::ite (temp_bool, one_bv, zero_bv);
89+ }
90+ case NEQ: {
91+ auto temp_bool = left != right;
92+ return z3::ite (temp_bool, one_bv, zero_bv);
93+ }
94+ case LT: {
95+ auto temp_bool = left < right;
96+ return z3::ite (temp_bool, one_bv, zero_bv);
97+ }
98+ case LEQ: {
99+ auto temp_bool = left <= right;
100+ return z3::ite (temp_bool, one_bv, zero_bv);
101+ }
102+ case GT: {
103+ auto temp_bool = left > right;
104+ return z3::ite (temp_bool, one_bv, zero_bv);
105+ }
106+ case GEQ: {
107+ auto temp_bool = left >= right;
108+ return z3::ite (temp_bool, one_bv, zero_bv);
109+ }
110+ case ADD: {
111+ return left + right;
112+ }
113+ case SUB: {
114+ return left - right;
115+ }
116+ case MUL: {
117+ return left * right;
118+ }
119+ case DIV: {
120+ return left / right;
121+ }
122+ }
123+ }
124+ throw std::runtime_error (" Unsupported symbolic value type" );
125+ }
28126#endif // SMT_SOLVER_HPP
0 commit comments