Skip to content

Commit 528a5c0

Browse files
committed
fn calls: allow removal of memory attrs
1 parent 583b733 commit 528a5c0

File tree

3 files changed

+42
-12
lines changed

3 files changed

+42
-12
lines changed

ir/memory.cpp

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1747,6 +1747,10 @@ Memory::mkFnRet(const char *name0, const vector<PtrInput> &ptr_inputs,
17471747
return { std::move(p).release(), {} };
17481748
}
17491749

1750+
expr Memory::CallState::writes(unsigned idx) const {
1751+
return writes_block.extract(idx, idx) == 1;
1752+
}
1753+
17501754
Memory::CallState Memory::CallState::mkIf(const expr &cond,
17511755
const CallState &then,
17521756
const CallState &els) {
@@ -1764,22 +1768,24 @@ Memory::CallState Memory::CallState::mkIf(const expr &cond,
17641768
els.non_local_block_val[i]));
17651769
}
17661770
}
1771+
ret.writes_block = expr::mkIf(cond, then.writes_block, els.writes_block);
17671772
ret.writes_args = expr::mkIf(cond, then.writes_args, els.writes_args);
17681773
ret.non_local_liveness = expr::mkIf(cond, then.non_local_liveness,
17691774
els.non_local_liveness);
17701775
return ret;
17711776
}
17721777

17731778
expr Memory::CallState::operator==(const CallState &rhs) const {
1774-
if (empty != rhs.empty)
1779+
if (non_local_liveness.isValid() != rhs.non_local_liveness.isValid())
17751780
return false;
1776-
if (empty)
1781+
if (!non_local_liveness.isValid())
17771782
return true;
17781783

17791784
expr ret = non_local_liveness == rhs.non_local_liveness;
17801785
for (unsigned i = 0, e = non_local_block_val.size(); i != e; ++i) {
17811786
ret &= non_local_block_val[i] == rhs.non_local_block_val[i];
17821787
}
1788+
ret &= writes_block == rhs.writes_block;
17831789
if (writes_args.isValid())
17841790
ret &= writes_args == rhs.writes_args;
17851791
return ret;
@@ -1790,7 +1796,21 @@ Memory::mkCallState(const string &fnname, bool nofree, unsigned num_ptr_args,
17901796
const SMTMemoryAccess &access) {
17911797
assert(has_fncall);
17921798
CallState st;
1793-
st.empty = false;
1799+
1800+
{
1801+
unsigned num_blocks = 1;
1802+
unsigned limit = num_nonlocals_src - num_inaccessiblememonly_fns;
1803+
for (unsigned i = 0; i < limit; ++i) {
1804+
if (!always_nowrite(i, true, true))
1805+
++num_blocks;
1806+
}
1807+
st.writes_block = expr::mkUInt(0, num_blocks);
1808+
}
1809+
1810+
if (access.canWriteSomething().isFalse()) {
1811+
st.writes_args = expr::mkUInt(0, num_ptr_args);
1812+
return st;
1813+
}
17941814

17951815
// TODO: handle havoc of local blocks
17961816

@@ -1809,6 +1829,15 @@ Memory::mkCallState(const string &fnname, bool nofree, unsigned num_ptr_args,
18091829
st.non_local_block_val.emplace_back(
18101830
expr::mkFreshVar("blk_val", mk_block_val_array(i)));
18111831
}
1832+
st.writes_block = expr::mkFreshVar("writes_block", st.writes_block);
1833+
assert(st.writes_block.bits() == st.non_local_block_val.size());
1834+
}
1835+
else if (!only_write_inaccess.isFalse()) {
1836+
auto var = expr::mkFreshVar("writes_block", expr::mkUInt(0, 1));
1837+
if (st.writes_block.bits() > 1)
1838+
st.writes_block = expr::mkUInt(0, st.writes_block.bits()-1).concat(var);
1839+
else
1840+
st.writes_block = std::move(var);
18121841
}
18131842

18141843
st.writes_args
@@ -1844,8 +1873,8 @@ void Memory::setState(const Memory::CallState &st,
18441873
assert(is_fncall_mem(bid));
18451874
assert(non_local_block_val[bid].undef.empty());
18461875
auto &cur_val = non_local_block_val[bid].val;
1847-
cur_val
1848-
= mk_block_if(only_write_inaccess, st.non_local_block_val[0], cur_val);
1876+
cur_val = mk_block_if(only_write_inaccess && st.writes(0),
1877+
st.non_local_block_val[0], cur_val);
18491878
}
18501879

18511880
// TODO: MemoryAccess::Errno
@@ -1858,7 +1887,7 @@ void Memory::setState(const Memory::CallState &st,
18581887
if (always_nowrite(bid, true, true))
18591888
continue;
18601889

1861-
expr modifies = access.canWrite(MemoryAccess::Other);
1890+
expr modifies = access.canWrite(MemoryAccess::Other) && st.writes(idx);
18621891

18631892
if (!is_fncall_mem(bid)) {
18641893
unsigned arg_idx = 0;
@@ -1870,8 +1899,10 @@ void Memory::setState(const Memory::CallState &st,
18701899
access.canWrite(MemoryAccess::Args) &&
18711900
writes;
18721901

1902+
Pointer ptr(*this, ptr_in.val.value);
18731903
modifies |= cond &&
1874-
Pointer(*this, ptr_in.val.value).getBid() == bid;
1904+
!ptr.isNull() &&
1905+
ptr.getBid() == bid;
18751906
state->addUB(cond.implies(ptr_in.val.non_poison));
18761907
state->addUB(ptr_in.nowrite.implies(!writes));
18771908
++arg_idx;

ir/memory.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,10 +244,11 @@ class Memory {
244244
class CallState {
245245
std::vector<smt::expr> non_local_block_val;
246246
smt::expr non_local_liveness;
247+
smt::expr writes_block;
247248
smt::expr writes_args;
248-
bool empty = true;
249249

250250
public:
251+
smt::expr writes(unsigned idx) const;
251252
static CallState mkIf(const smt::expr &cond, const CallState &then,
252253
const CallState &els);
253254
smt::expr operator==(const CallState &rhs) const;

ir/state.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1181,10 +1181,8 @@ State::addFnCall(const string &name, vector<StateValue> &&inputs,
11811181
(noret || willret)
11821182
? expr(noret)
11831183
: expr::mkFreshVar((name + "#noreturn").c_str(), false),
1184-
memaccess.canWriteSomething().isFalse()
1185-
? Memory::CallState()
1186-
: memory.mkCallState(name, attrs.has(FnAttrs::NoFree),
1187-
I->first.args_ptr.size(), memaccess),
1184+
memory.mkCallState(name, attrs.has(FnAttrs::NoFree),
1185+
I->first.args_ptr.size(), memaccess),
11881186
std::move(ret_data) };
11891187

11901188
// add equality constraints between source's function calls

0 commit comments

Comments
 (0)