Skip to content

Commit 6dd52b2

Browse files
never build an expression twice
1 parent 1818f53 commit 6dd52b2

File tree

4 files changed

+37
-9
lines changed

4 files changed

+37
-9
lines changed

benchmarks/pldi2026/btree/compile.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
DEFAULT_FLAGS = [
1818
"-std=c++17",
1919
"-g",
20-
"-O0",
20+
"-O3",
2121
"-Wall",
2222
"-Wextra",
2323
"-DUSE_IMM",

benchmarks/pldi2026/btree/run.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ def run_all(targets: list[Path], action):
2323
continue
2424
file_name = file_path.name.removesuffix(".exe")
2525
output_path = f"{file_name}.output"
26+
if Path(output_path).exists():
27+
continue
2628
if action == "run":
2729
env = os.environ.copy()
2830
env.update({"OUTPUT_DIR": output_path})

headers/wasm/smt_solver.hpp

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "wasm/profile.hpp"
88
#include "z3++.h"
99
#include <array>
10+
#include <memory>
1011
#include <set>
1112
#include <string>
1213
#include <tuple>
@@ -15,15 +16,16 @@
1516
class Solver {
1617
public:
1718
Solver() {}
18-
std::optional<NumMap> solve(const std::vector<SymVal> &conditions) {
19+
std::optional<NumMap> solve(std::vector<SymVal> &conditions) {
1920
z3::solver z3_solver(z3_ctx);
2021
z3::check_result solver_result;
2122
{
23+
auto timer = ManagedTimer(TimeProfileKind::SOLVER);
2224
// make an conjunction of all conditions
2325
auto conjunction = to_z3_conjunction(conditions);
2426
// call z3 to solve the condition
25-
auto timer = ManagedTimer(TimeProfileKind::SOLVER);
26-
z3_solver.add(conjunction); // NOTE: half of the solver time is spent in solver.add
27+
// NOTE: half of the solver time is spent in solver.add
28+
z3_solver.add(conjunction);
2729
solver_result = z3_solver.check();
2830
}
2931
switch (solver_result) {
@@ -56,9 +58,9 @@ class Solver {
5658
}
5759

5860
private:
59-
z3::expr to_z3_conjunction(const std::vector<SymVal> &conditions) {
61+
z3::expr to_z3_conjunction(std::vector<SymVal> &conditions) {
6062
z3::expr conjunction = z3_ctx.bool_val(true);
61-
for (const auto &cond : conditions) {
63+
for (auto &cond : conditions) {
6264
auto z3_cond = build_z3_expr(cond);
6365
conjunction = conjunction && z3_cond != z3_ctx.bv_val(0, 32);
6466
}
@@ -70,10 +72,13 @@ class Solver {
7072
}
7173

7274
z3::context z3_ctx;
73-
z3::expr build_z3_expr(const SymVal &sym_val);
75+
z3::expr build_z3_expr(SymVal &sym_val);
76+
77+
private:
78+
z3::expr build_z3_expr_aux(SymVal &sym_val);
7479
};
7580

76-
inline z3::expr Solver::build_z3_expr(const SymVal &sym_val) {
81+
inline z3::expr Solver::build_z3_expr_aux(SymVal &sym_val) {
7782
if (auto sym = std::dynamic_pointer_cast<Symbol>(sym_val.symptr)) {
7883
return z3_ctx.bv_const(("s_" + std::to_string(sym->get_id())).c_str(), 32);
7984
} else if (auto concrete =
@@ -150,4 +155,13 @@ inline z3::expr Solver::build_z3_expr(const SymVal &sym_val) {
150155
}
151156
throw std::runtime_error("Unsupported symbolic value type");
152157
}
158+
159+
inline z3::expr Solver::build_z3_expr(SymVal &sym_val) {
160+
if (sym_val.z3_expr) {
161+
return *sym_val.z3_expr;
162+
}
163+
auto e = build_z3_expr_aux(sym_val);
164+
sym_val.z3_expr = std::make_shared<z3::expr>(e);
165+
return e;
166+
}
153167
#endif // SMT_SOLVER_HPP

headers/wasm/symbolic_rt.hpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "immer/vector_transient.hpp"
1111
#include "profile.hpp"
1212
#include "utils.hpp"
13+
#include "z3++.h"
1314
#include <cassert>
1415
#include <cstddef>
1516
#include <cstdint>
@@ -90,6 +91,7 @@ static std::shared_ptr<SmallBV> ZeroByte =
9091

9192
struct SymVal {
9293
std::shared_ptr<Symbolic> symptr;
94+
std::shared_ptr<z3::expr> z3_expr;
9395

9496
SymVal() : symptr(ZERO) {}
9597
SymVal(std::shared_ptr<Symbolic> symptr) : symptr(symptr) {}
@@ -226,11 +228,21 @@ inline SymVal SymVal::make_binary(Operation op, const SymVal &lhs,
226228
assert(lhs.symptr != nullptr && rhs.symptr != nullptr);
227229
return SymVal(SymBookKeeper.allocate<SymBinary>(op, lhs, rhs));
228230
}
231+
static std::unordered_map<int, SymVal> SymbolCache;
232+
229233
inline SymVal SymVal::makeSymbolic() const {
230234
auto concrete = dynamic_cast<SymConcrete *>(symptr.get());
231235
if (concrete) {
232236
// If the symbolic value is a concrete value, use it to create a symbol
233-
return SymVal(SymBookKeeper.allocate<Symbol>(concrete->value.toInt()));
237+
auto id = concrete->value.toInt();
238+
auto it = SymbolCache.find(id);
239+
if (it != SymbolCache.end()) {
240+
return it->second;
241+
}
242+
auto sym = Symbol(id);
243+
auto ptr = SymBookKeeper.allocate<Symbol>(sym);
244+
return SymVal(ptr);
245+
234246
} else {
235247
throw std::runtime_error(
236248
"Cannot make symbolic a non-concrete symbolic value");

0 commit comments

Comments
 (0)