fix two false-positive cases of escaped blocks on fn call
fixes a few examples of but not all yet
MODIFY
ir/memory.cpp
ir/memory.cpp
@@ -947,9 +947,7 @@ void Memory::store(const Pointer &ptr,
for (auto &[offset, val] : data) {
Byte byte(*this, expr(val));
- // TODO: check impact of !byte.isPtr().isFalse()
- if (byte.isPtr().isTrue())
- escapeLocalPtr(byte.ptrValue());
+ escapeLocalPtr(byte.ptrValue(), byte.isPtr() && byte.ptrNonpoison());
}
unsigned bytes = data.size() * (bits_byte/8);
@@ -1067,7 +1065,7 @@ void Memory::mkNonlocalValAxioms(bool skip_consts) {
return;
for (unsigned i = 0, e = numNonlocals(); i != e; ++i) {
- if (always_nowrite(i))
+ if (always_noread(i))
continue;
Byte byte(*this, non_local_block_val[i].val.load(offset));
@@ -2109,7 +2107,10 @@ expr Memory::checkNocapture() const {
return res;
}
-void Memory::escapeLocalPtr(const expr &ptr) {
+void Memory::escapeLocalPtr(const expr &ptr, const expr &is_ptr) {
+ if (is_ptr.isFalse())
+ return;
+
if (next_local_bid == 0 ||
escaped_local_blks.isFullUpToAlias(true) == (int)next_local_bid-1)
return;

MODIFY
ir/memory.h
ir/memory.h
@@ -322,7 +322,7 @@ public:
// Returns true if a nocapture pointer byte is not in the memory.
smt::expr checkNocapture() const;
- void escapeLocalPtr(const smt::expr &ptr);
+ void escapeLocalPtr(const smt::expr &ptr, const smt::expr &is_ptr);
static Memory mkIf(const smt::expr &cond, const Memory &then,
const Memory &els);

MODIFY
ir/state.cpp
ir/state.cpp
@@ -818,8 +818,8 @@ State::addFnCall(const string &name, vector<StateValue> &&inputs,
if (writes_memory) {
for (auto &v : ptr_inputs) {
- if (!v.byval && !v.nocapture && !v.val.non_poison.isFalse())
- memory.escapeLocalPtr(v.val.value);
+ if (!v.byval && !v.nocapture)
+ memory.escapeLocalPtr(v.val.value, v.val.non_poison);
}
}

MODIFY
smt/expr.cpp
smt/expr.cpp
@@ -2107,10 +2107,14 @@ set<expr> expr::leafs(unsigned max) const {
if (!seen.emplace(val()).second)
continue;
- expr cond, then, els;
+ expr cond, then, els, e;
+ unsigned high, low;
if (val.isIf(cond, then, els)) {
worklist.emplace_back(std::move(then));
worklist.emplace_back(std::move(els));
+ } else if (val.isExtract(e, high, low) && e.isIf(cond, then, els)) {
+ worklist.emplace_back(then.extract(high, low));
+ worklist.emplace_back(els.extract(high, low));
} else {
ret.emplace(std::move(val));
}

ADD
tests/alive-tv/calls/escape3.srctgt.ll
+declare ptr @f(ptr)
+declare void @g(ptr)
+
+define void @src(ptr %dummy, ptr %operands) {
+ %src = alloca ptr, align 8
+ %ptr = load ptr, ptr %operands, align 8
+ %call = call ptr @f(ptr %ptr)
+ call void @g(ptr %call)
+ ret void
+}
+
+define void @tgt(ptr %dummy, ptr %operands) {
+ %ptr = load ptr, ptr %operands, align 8
+ %call = call ptr @f(ptr %ptr)
+ call void @g(ptr %call)
+ ret void
+}

ADD
tests/alive-tv/calls/escape4.srctgt.ll
+%struct.ix86_address = type { ptr, ptr, ptr, i64, i32 }
+
+@__FUNCTION__.aligned_operand = external constant [8 x i8]
+
+declare void @fancy_abort(ptr)
+
+define i32 @src(ptr %op) {
+entry:
+ %parts = alloca %struct.ix86_address, i32 0, align 8
+ %0 = load ptr, ptr %op, align 8
+ %call16 = call i32 @ix86_decompose_address(ptr %0)
+ br i1 false, label %if.end19, label %if.then18
+
+if.then18:
+ call void @fancy_abort(ptr @__FUNCTION__.aligned_operand)
+ unreachable
+
+if.end19:
+ %tobool20 = icmp ne ptr %0, null
+ br i1 %tobool20, label %if.then21, label %if.then21
+
+if.then21:
+ br label %if.then21
+
+if.then21:
+ ret i32 0
+}
+
+define i32 @tgt(ptr %op) {
+entry:
+ %0 = load ptr, ptr %op, align 8
+ %call16 = call i32 @ix86_decompose_address(ptr %0)
+ call void @fancy_abort(ptr @__FUNCTION__.aligned_operand)
+ unreachable
+}
+
+declare i32 @ix86_decompose_address(ptr)

fix two false-positive cases of escaped blocks on fn call
fixes a few examples of #556, but not all yet