state: use disjoint expr to track memory as well
MODIFY
ir/memory.cpp
ir/memory.cpp
@@ -639,4 +639,14 @@ Memory Memory::mkIf(const expr &cond, const Memory &then, const Memory &els) {
return ret;
}
+bool Memory::operator<(const Memory &rhs) const {
+ // FIXME: remove this once we move to C++20
+ return
+ tie(non_local_block_val, local_block_val, non_local_block_liveness,
+ local_block_liveness, local_blk_addr, local_blk_size, local_blk_kind) <
+ tie(rhs.non_local_block_val, rhs.local_block_val,
+ rhs.non_local_block_liveness, rhs.local_block_liveness,
+ rhs.local_blk_addr, rhs.local_blk_size, rhs.local_blk_kind);
+}
+
}

MODIFY
ir/memory.h
ir/memory.h
@@ -172,6 +172,9 @@ public:
unsigned bitsByte() const { return 1 + 1 + bitsBid() + bitsOffset() + 3; }
unsigned bitsPtrSize() const { return bits_size_t; }
+ // for container use only
+ bool operator<(const Memory &rhs) const;
+
friend class Pointer;
};

MODIFY
ir/state.cpp
ir/state.cpp
@@ -15,7 +15,8 @@ namespace IR {
State::State(const Function &f, bool source)
: f(f), source(source), memory(*this, f.isLittleEndian()),
- return_domain(false), return_val(f.getType().getDummyValue(false)) {}
+ return_domain(false), return_val(f.getType().getDummyValue(false)),
+ return_memory(memory) {}
void State::resetGlobals() {
Memory::resetGlobalData();
@@ -93,7 +94,8 @@ bool State::startBB(const BasicBlock &bb) {
domain.first = false;
domain.second.clear();
- bool first = true;
+
+ DisjointExpr<Memory> in_memory;
for (auto &[src, data] : I->second) {
(void)src;
@@ -101,15 +103,15 @@ bool State::startBB(const BasicBlock &bb) {
auto &[cond, vars] = dom;
domain.first |= cond;
domain.second.insert(vars.begin(), vars.end());
-
- if (first) {
- memory = mem;
- first = false;
- } else {
- memory = Memory::mkIf(cond, mem, memory);
+ in_memory.add(mem, cond);
}
- }
- return !domain.first.isFalse();
+
+ if (domain.first.isFalse())
+ return false;
+
+ memory = in_memory();
+
+ return true;
}
void State::addJump(const BasicBlock &dst, expr &&cond) {
@@ -150,6 +152,7 @@ void State::addCondJump(const StateValue &cond, const BasicBlock &dst_true,
void State::addReturn(const StateValue &val) {
return_val.add(val, domain.first);
+ return_memory.add(memory, domain.first);
return_domain |= domain.first;
return_undef_vars.insert(undef_vars.begin(), undef_vars.end());
return_undef_vars.insert(domain.second.begin(), domain.second.end());

MODIFY
ir/state.h
ir/state.h
@@ -62,6 +62,7 @@ private:
// return_domain: a boolean expression describing return condition
smt::expr return_domain;
smt::DisjointExpr<StateValue> return_val;
+ smt::DisjointExpr<Memory> return_memory;
std::set<smt::expr> return_undef_vars;
public:

MODIFY
smt/exprs.cpp
smt/exprs.cpp
@@ -28,4 +28,8 @@ expr FunctionExpr::operator()(expr &key) const {
return disj();
}
+bool FunctionExpr::operator<(const FunctionExpr &rhs) const {
+ return tie(fn, default_val) < tie(rhs.fn, rhs.default_val);
+}
+
}

MODIFY
smt/exprs.h
smt/exprs.h
@@ -13,7 +13,7 @@ namespace smt {
template <typename T>
class DisjointExpr {
std::map<T, expr> vals; // val -> domain
- T default_val;
+ std::optional<T> default_val;
public:
DisjointExpr() {}
@@ -41,7 +41,7 @@ public:
ret = ret ? T::mkIf(domain, val, *ret) : val;
}
- return ret.value_or(default_val);
+ return ret ? *ret : default_val.value();
}
};
@@ -57,6 +57,9 @@ public:
void add(const FunctionExpr &other);
void del(const expr &key);
expr operator()(expr &key) const;
+
+ // for container use only
+ bool operator<(const FunctionExpr &rhs) const;
};
}

state: use disjoint expr to track memory as well