Skip to content

Commit

Permalink
implement based-on semantics of memory(argmem) attribute.
Browse files Browse the repository at this point in the history
This implementation doesn't take escaped pointers through ptr2int into account
#969
  • Loading branch information
nunoplopes committed Nov 21, 2023
1 parent 40ed5a5 commit 535c2e4
Show file tree
Hide file tree
Showing 12 changed files with 74 additions and 28 deletions.
4 changes: 4 additions & 0 deletions ir/attrs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,10 @@ bool MemoryAccess::canOnlyWrite(AccessType ty) const {
return canWrite(ty);
}

bool MemoryAccess::canAccessAnything() const {
return canReadAnything() && canWriteAnything();
}

bool MemoryAccess::canReadAnything() const {
for (unsigned i = 0; i < NumTypes; ++i) {
if (!canRead(AccessType(i)))
Expand Down
4 changes: 3 additions & 1 deletion ir/attrs.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class MemoryAccess final {
bool canWrite(AccessType ty) const;
bool canOnlyRead(AccessType ty) const;
bool canOnlyWrite(AccessType ty) const;
bool canAccessAnything() const;
bool canReadAnything() const;
bool canWriteAnything() const;
bool canReadSomething() const;
Expand Down Expand Up @@ -64,7 +65,8 @@ class ParamAttrs final {
NoUndef = 1<<6, Align = 1<<7, Returned = 1<<8,
NoAlias = 1<<9, DereferenceableOrNull = 1<<10,
AllocPtr = 1<<11, AllocAlign = 1<<12,
ZeroExt = 1<<13, SignExt = 1<<14, NoFPClass = 1<<15 };
ZeroExt = 1<<13, SignExt = 1<<14, NoFPClass = 1<<15,
IsArg = 1<<16 };

ParamAttrs(unsigned bits = None) : bits(bits) {}

Expand Down
1 change: 1 addition & 0 deletions ir/globals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ bool has_write_fncall = true;
bool has_nocapture = true;
bool has_noread = true;
bool has_nowrite = true;
bool has_ptr_arg = true;
bool has_null_block = true;
bool null_is_dereferenceable = false;
bool does_int_mem_access = true;
Expand Down
1 change: 1 addition & 0 deletions ir/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ extern bool has_write_fncall;
extern bool has_nocapture;
extern bool has_noread;
extern bool has_nowrite;
extern bool has_ptr_arg;

/// Whether there null pointers appear in the program
extern bool has_null_pointer;
Expand Down
20 changes: 4 additions & 16 deletions ir/instr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2227,18 +2227,6 @@ static void eq_bids(OrExpr &acc, Memory &m, const Type &t,
}
}

static expr ptr_only_args(State &s, const Pointer &p) {
expr bid = p.getBid();
auto &m = s.getMemory();

OrExpr e;
for (auto &in : s.getFn().getInputs()) {
if (hasPtr(in.getType()))
eq_bids(e, m, in.getType(), s[in], bid);
}
return e();
}

static void check_can_load(State &s, const expr &p0) {
auto &attrs = s.getFn().getFnAttrs();
if (attrs.mem.canReadAnything())
Expand All @@ -2251,10 +2239,10 @@ static void check_can_load(State &s, const expr &p0) {
expr nonreadable = false;

(attrs.mem.canRead(MemoryAccess::Globals) ? readable : nonreadable)
|= p.isWritableGlobal();
|= p.isWritableGlobal() && !p.isBasedOnArg();

(attrs.mem.canRead(MemoryAccess::Args) ? readable : nonreadable)
|= ptr_only_args(s, p);
|= p.isBasedOnArg();

s.addUB(std::move(readable));
s.addUB(!nonreadable);
Expand All @@ -2273,10 +2261,10 @@ static void check_can_store(State &s, const expr &p0) {
expr nonwritable = false;

(attrs.mem.canWrite(MemoryAccess::Globals) ? writable : nonwritable)
|= p.isWritableGlobal();
|= p.isWritableGlobal() && !p.isBasedOnArg();

(attrs.mem.canWrite(MemoryAccess::Args) ? writable : nonwritable)
|= ptr_only_args(s, p);
|= p.isBasedOnArg();

s.addUB(std::move(writable));
s.addUB(!nonwritable);
Expand Down
11 changes: 8 additions & 3 deletions ir/memory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1294,9 +1294,12 @@ void Memory::markByVal(unsigned bid, bool is_const) {
byval_blks.emplace_back(bid, is_const);
}

expr Memory::mkInput(const char *name, const ParamAttrs &attrs) {
expr Memory::mkInput(const char *name, const ParamAttrs &attrs0) {
unsigned max_bid = has_null_block + num_globals_src + next_ptr_input++;
assert(max_bid < num_nonlocals_src);

auto attrs = attrs0;
attrs.set(ParamAttrs::IsArg);
Pointer p(*this, name, false, false, false, attrs);
auto bid = p.getShortBid();

Expand All @@ -1314,8 +1317,8 @@ expr Memory::mkInput(const char *name, const ParamAttrs &attrs) {
return std::move(p).release();
}

pair<expr, expr> Memory::mkUndefInput(const ParamAttrs &attrs) const {
bool nonnull = attrs.has(ParamAttrs::NonNull);
pair<expr, expr> Memory::mkUndefInput(const ParamAttrs &attrs0) const {
bool nonnull = attrs0.has(ParamAttrs::NonNull);
unsigned log_offset = ilog2_ceil(bits_for_offset, false);
unsigned bits_undef = bits_for_offset + nonnull * log_offset;
expr undef = expr::mkFreshVar("undef", expr::mkUInt(0, bits_undef));
Expand All @@ -1329,6 +1332,8 @@ pair<expr, expr> Memory::mkUndefInput(const ParamAttrs &attrs) const {
one << var.zextOrTrunc(bits_for_offset));
offset = undef.extract(bits_undef - 1, log_offset) | shl;
}
auto attrs = attrs0;
attrs.set(ParamAttrs::IsArg);
return
{ Pointer(*this, expr::mkUInt(0, bits_for_bid), offset, attrs).release(),
std::move(undef) };
Expand Down
21 changes: 14 additions & 7 deletions ir/pointer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ static expr attr_to_bitvec(const ParamAttrs &attrs) {
bits |= to_bit(has_nocapture, ParamAttrs::NoCapture);
bits |= to_bit(has_noread, ParamAttrs::NoRead);
bits |= to_bit(has_nowrite, ParamAttrs::NoWrite);
bits |= to_bit(has_ptr_arg, ParamAttrs::IsArg);
return expr::mkUInt(bits, bits_for_ptrattrs);
}

Expand Down Expand Up @@ -621,17 +622,23 @@ expr Pointer::isNocapture(bool simplify) const {
return p.extract(0, 0) == 1;
}

#define GET_ATTR(attr, idx) \
if (!attr) \
return false; \
unsigned idx_ = idx; \
return p.extract(idx_, idx_) == 1;

expr Pointer::isNoRead() const {
if (!has_noread)
return false;
return p.extract(has_nocapture, has_nocapture) == 1;
GET_ATTR(has_noread, (unsigned)has_nocapture);
}

expr Pointer::isNoWrite() const {
if (!has_nowrite)
return false;
unsigned idx = (unsigned)has_nocapture + (unsigned)has_noread;
return p.extract(idx, idx) == 1;
GET_ATTR(has_nowrite, (unsigned)has_nocapture + (unsigned)has_noread);
}

expr Pointer::isBasedOnArg() const {
GET_ATTR(has_ptr_arg, (unsigned)has_nocapture + (unsigned)has_noread +
(unsigned)has_nowrite);
}

Pointer Pointer::mkNullPointer(const Memory &m) {
Expand Down
1 change: 1 addition & 0 deletions ir/pointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ class Pointer {
smt::expr isNocapture(bool simplify = true) const;
smt::expr isNoRead() const;
smt::expr isNoWrite() const;
smt::expr isBasedOnArg() const;

smt::expr refined(const Pointer &other) const;
smt::expr fninputRefined(const Pointer &other, std::set<smt::expr> &undef,
Expand Down
8 changes: 8 additions & 0 deletions tests/alive-tv/attrs/argmemonly4.srctgt.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
define i32 @src(ptr %0) memory(read, argmem: none) {
%2 = load i32, ptr %0, align 4
ret i32 %2
}

define i32 @tgt(ptr %0) memory(read, argmem: none) {
unreachable
}
12 changes: 12 additions & 0 deletions tests/alive-tv/attrs/argmemonly5.srctgt.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
@x = external global i8

define i8 @src(ptr %0) memory(read, argmem: none) {
%2 = load i8, ptr @x, align 1
ret i8 %2
}

define i8 @tgt(ptr %0) memory(none) {
unreachable
}

; ERROR: Source is more defined than target
11 changes: 11 additions & 0 deletions tests/alive-tv/attrs/argmemonly6.srctgt.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
@x = external global i8

define i8 @src(ptr %0) memory(read, argmem: none) {
%2 = load i8, ptr @x, align 1
ret i8 %2
}

define i8 @tgt(ptr %0) memory(read, argmem: none) {
%2 = load i8, ptr @x, align 1
ret i8 %2
}
8 changes: 7 additions & 1 deletion tools/transform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -955,6 +955,7 @@ static void calculateAndInitConstants(Transform &t) {
observes_addresses = false;
bool does_any_byte_access = false;
has_indirect_fncalls = false;
has_ptr_arg = false;

set<string> inaccessiblememonly_fns;
num_inaccessiblememonly_fns = 0;
Expand Down Expand Up @@ -987,6 +988,8 @@ static void calculateAndInitConstants(Transform &t) {
if (!i)
continue;

has_ptr_arg |= hasPtr(i->getType());

update_min_vect_sz(i->getType());

if (i->hasAttribute(ParamAttrs::Dereferenceable)) {
Expand Down Expand Up @@ -1151,7 +1154,9 @@ static void calculateAndInitConstants(Transform &t) {
has_nocapture = has_attr(ParamAttrs::NoCapture);
has_noread = has_attr(ParamAttrs::NoRead);
has_nowrite = has_attr(ParamAttrs::NoWrite);
bits_for_ptrattrs = has_nocapture + has_noread + has_nowrite;
has_ptr_arg &= !t.src.getFnAttrs().mem.canAccessAnything() ||
!t.tgt.getFnAttrs().mem.canAccessAnything();
bits_for_ptrattrs = has_nocapture + has_noread + has_nowrite + has_ptr_arg;

// ceil(log2(maxblks)) + 1 for local bit
bits_for_bid = max(1u, ilog2_ceil(max(num_locals, num_nonlocals), false))
Expand Down Expand Up @@ -1231,6 +1236,7 @@ static void calculateAndInitConstants(Transform &t) {
<< "\ndoes_mem_access: " << does_mem_access
<< "\ndoes_ptr_mem_access: " << does_ptr_mem_access
<< "\ndoes_int_mem_access: " << does_int_mem_access
<< "\nhas_ptr_arg: " << has_ptr_arg
<< '\n';
}

Expand Down

0 comments on commit 535c2e4

Please sign in to comment.