Skip to content

Commit

Permalink
add support for !dereferenceable metadata in load/store instructions
Browse files Browse the repository at this point in the history
  • Loading branch information
nunoplopes committed Dec 13, 2023
1 parent 81969b5 commit 0670157
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 19 deletions.
5 changes: 0 additions & 5 deletions ir/attrs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -328,11 +328,6 @@ void ParamAttrs::merge(const ParamAttrs &other) {
align = max(align, other.align);
}

static expr merge(pair<AndExpr, expr> e) {
e.first.add(std::move(e.second));
return std::move(e.first)();
}

static expr
encodePtrAttrs(State &s, const expr &ptrvalue, uint64_t derefBytes,
uint64_t derefOrNullBytes, uint64_t align, bool nonnull,
Expand Down
42 changes: 31 additions & 11 deletions ir/instr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3164,10 +3164,18 @@ Assume::Assume(Value &cond, Kind kind)

Assume::Assume(vector<Value *> &&args0, Kind kind)
: Instr(Type::voidTy, "assume"), args(std::move(args0)), kind(kind) {
if (args.size() == 1)
assert(kind == AndNonPoison || kind == WellDefined || kind == NonNull);
else {
assert(kind == Align && args.size() == 2);
switch (kind) {
case AndNonPoison:
case WellDefined:
case NonNull:
assert(args.size() == 1);
break;

case Align:
case Dereferenceable:
case DereferenceableOrNull:
assert(args.size() == 2);
break;
}
}

Expand All @@ -3191,10 +3199,12 @@ void Assume::rauw(const Value &what, Value &with) {
void Assume::print(ostream &os) const {
const char *str = nullptr;
switch (kind) {
case AndNonPoison: str = "assume "; break;
case WellDefined: str = "assume_welldefined "; break;
case Align: str = "assume_align "; break;
case NonNull: str = "assume_nonnull "; break;
case AndNonPoison: str = "assume "; break;
case WellDefined: str = "assume_welldefined "; break;
case Align: str = "assume_align "; break;
case Dereferenceable: str = "assume_dereferenceable "; break;
case DereferenceableOrNull: str = "assume_dereferenceable_or_null "; break;
case NonNull: str = "assume_nonnull "; break;
}
os << str;

Expand Down Expand Up @@ -3226,11 +3236,19 @@ StateValue Assume::toSMT(State &s) const {
s.addGuardableUB(Pointer(s.getMemory(), ptr).isAligned(align));
break;
}
case Dereferenceable:
case DereferenceableOrNull: {
const auto &vptr = s.getAndAddPoisonUB(*args[0]).value;
const auto &bytes = s.getAndAddPoisonUB(*args[1]).value;
Pointer ptr(s.getMemory(), vptr);
expr nonnull = kind == DereferenceableOrNull ? !ptr.isNull() : false;
s.addUB(nonnull || merge(ptr.isDereferenceable(bytes, 1, false)));
break;
}
case NonNull: {
// assume(ptr)
const auto &vptr = s.getAndAddPoisonUB(*args[0]);
Pointer ptr(s.getMemory(), vptr.value);
s.addGuardableUB(!ptr.isNull());
const auto &ptr = s.getAndAddPoisonUB(*args[0]).value;
s.addGuardableUB(!Pointer(s.getMemory(), ptr).isNull());
break;
}
}
Expand All @@ -3244,6 +3262,8 @@ expr Assume::getTypeConstraints(const Function &f) const {
case AndNonPoison:
return args[0]->getType().enforceIntType();
case Align:
case Dereferenceable:
case DereferenceableOrNull:
return args[0]->getType().enforcePtrType() &&
args[1]->getType().enforceIntType();
case NonNull:
Expand Down
8 changes: 5 additions & 3 deletions ir/instr.h
Original file line number Diff line number Diff line change
Expand Up @@ -587,9 +587,11 @@ class Assume final : public Instr {
public:
enum Kind {
AndNonPoison, /// cond should be non-poison and hold
WellDefined, /// cond only needs to be well defined (can be false)
Align, /// args[0] satisfies alignment args[1]
NonNull /// args[0] is a nonnull pointer
WellDefined, /// cond only needs to be well defined (can be false)
Align, /// args[0] satisfies alignment args[1]
Dereferenceable, /// args[0] is dereferenceable at least args[1]
DereferenceableOrNull, /// args[0] is null or deref least args[1]
NonNull /// args[0] is a nonnull pointer
};

private:
Expand Down
19 changes: 19 additions & 0 deletions llvm_util/llvm2alive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,14 @@ FpExceptionMode parse_exceptions(llvm::Instruction &i) {
}
}

Value* get_ptr(Instr &i) {
for (auto *op : i.operands()) {
if (op->getType().isPtrType())
return op;
}
UNREACHABLE();
}

bool hit_limits;
unsigned constexpr_idx;
unsigned copy_idx;
Expand Down Expand Up @@ -1282,6 +1290,17 @@ class llvm2alive_ : public llvm::InstVisitor<llvm2alive_, unique_ptr<Instr>> {
BB->addInstr(make_unique<Assume>(*i, Assume::WellDefined));
break;

case LLVMContext::MD_dereferenceable:
case LLVMContext::MD_dereferenceable_or_null: {
auto kind = ID == LLVMContext::MD_dereferenceable
? Assume::Dereferenceable : Assume::DereferenceableOrNull;
auto bytes = get_operand(
llvm::mdconst::extract<llvm::ConstantInt>(Node->getOperand(0)));
BB->addInstr(
make_unique<Assume>(vector<Value*>{get_ptr(*i), bytes}, kind));
break;
}

// non-relevant for correctness
case LLVMContext::MD_loop:
case LLVMContext::MD_nosanitize:
Expand Down
5 changes: 5 additions & 0 deletions smt/exprs.h
Original file line number Diff line number Diff line change
Expand Up @@ -212,3 +212,8 @@ class FunctionExpr {
};

}

static inline smt::expr merge(std::pair<smt::AndExpr, smt::expr> e) {
e.first.add(std::move(e.second));
return std::move(e.first)();
}
11 changes: 11 additions & 0 deletions tests/alive-tv/memory/dereferenceable_metadata.srctgt.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
define void @src(ptr %0) {
load <6 x i16>, ptr %0, align 16, !dereferenceable !0
ret void
}

define void @tgt(ptr %0) {
load i128, ptr %0, align 16
ret void
}

!0 = !{ i32 16 }

0 comments on commit 0670157

Please sign in to comment.