Factor out FnAttrs class
MODIFY
ir/attrs.h
ir/attrs.h
@@ -35,4 +35,33 @@ public:
void set(Attribute a) { bits = bits | (unsigned)a; }
};
+
+class FnAttrs final {
+public:
+ enum Attribute { None = 0, NoRead = 1 << 0, NoWrite = 1 << 1,
+ ArgMemOnly = 1 << 2, NNaN = 1 << 3, NoReturn = 1 << 4 };
+
+ unsigned bits;
+
+ FnAttrs(unsigned bits = None) : bits(bits) {}
+
+ std::string str() const {
+ std::string ret;
+ if (bits & NoRead)
+ ret += " noread";
+ if (bits & NoWrite)
+ ret += " nowrite";
+ if (bits & ArgMemOnly)
+ ret += " argmemonly";
+ if (bits & NNaN)
+ ret += " NNaN";
+ if (bits & NoReturn)
+ ret += " noreturn";
+ return ret;
+ }
+
+ bool has(Attribute a) const { return (bits & a) != 0; }
+ void set(Attribute a) { bits = bits | (unsigned)a; }
+};
+
}

MODIFY
ir/instr.cpp
ir/instr.cpp
@@ -1302,18 +1302,7 @@ void FnCall::print(ostream &os) const {
os << attrs.str() << *arg;
first = false;
}
- os << ')';
-
- if (flags & NoRead)
- os << " noread";
- if (flags & NoWrite)
- os << " nowrite";
- if (flags & ArgMemOnly)
- os << " argmemonly";
- if (flags & NNaN)
- os << " NNaN";
- if (flags & NoReturn)
- os << " noreturn";
+ os << ')' << attrs.str();
if (!valid)
os << "\t; WARNING: unknown known function";
@@ -1350,17 +1339,17 @@ static void unpack_ret_ty (vector<Type*> &out_types, Type &ty) {
}
static StateValue pack_return(Type &ty, vector<StateValue> &vals,
- unsigned flags, unsigned &idx) {
+ const FnAttrs &attrs, unsigned &idx) {
if (auto agg = ty.getAsAggregateType()) {
vector<StateValue> vs;
for (unsigned i = 0, e = agg->numElementsConst(); i != e; ++i) {
- vs.emplace_back(pack_return(agg->getChild(i), vals, flags, idx));
+ vs.emplace_back(pack_return(agg->getChild(i), vals, attrs, idx));
}
return agg->aggregateVals(vs);
}
auto &ret = vals[idx++];
- if (ty.isFloatType() && (flags & FnCall::NNaN))
+ if (ty.isFloatType() && attrs.has(FnAttrs::NNaN))
ret.non_poison &= !ret.value.isNaN();
return ret;
}
@@ -1387,15 +1376,14 @@ StateValue FnCall::toSMT(State &s) const {
unsigned idx = 0;
auto ret = s.addFnCall(fnName_mangled.str(), move(inputs), move(ptr_inputs),
- out_types, !(flags & NoRead), !(flags & NoWrite),
- flags & ArgMemOnly);
+ out_types, attrs);
- if (flags & NoReturn) {
+ if (attrs.has(FnAttrs::NoReturn)) {
// TODO: Even if a function call doesn't have noreturn, it can possibly
// exit. Relevant bug: https://bugs.llvm.org/show_bug.cgi?id=27953
s.addNoReturn();
}
- return isVoid() ? StateValue() : pack_return(getType(), ret, flags, idx);
+ return isVoid() ? StateValue() : pack_return(getType(), ret, attrs, idx);
}
expr FnCall::getTypeConstraints(const Function &f) const {
@@ -1405,7 +1393,7 @@ expr FnCall::getTypeConstraints(const Function &f) const {
unique_ptr<Instr> FnCall::dup(const string &suffix) const {
auto r = make_unique<FnCall>(getType(), getName() + suffix, string(fnName),
- flags, valid);
+ FnAttrs(attrs), valid);
r->args = args;
return r;
}

MODIFY
ir/instr.h
ir/instr.h
@@ -188,24 +188,22 @@ public:
class FnCall final : public Instr {
-public:
- enum Flags { None = 0, NoRead = 1 << 0, NoWrite = 1 << 1, ArgMemOnly = 1 << 2,
- NNaN = 1 << 3, NoReturn = 1 << 4 };
private:
std::string fnName;
std::vector<std::pair<Value*, ParamAttrs>> args;
- unsigned flags;
+ FnAttrs attrs;
bool valid;
public:
FnCall(Type &type, std::string &&name, std::string &&fnName,
- unsigned flags = None, bool valid = true)
- : Instr(type, std::move(name)), fnName(std::move(fnName)), flags(flags),
- valid(valid) {}
+ FnAttrs &&attrs = FnAttrs::None, bool valid = true)
+ : Instr(type, std::move(name)), fnName(std::move(fnName)),
+ attrs(std::move(attrs)), valid(valid) {}
void addArg(Value &arg, ParamAttrs &&attrs);
const auto& getFnName() const { return fnName; }
const auto& getArgs() const { return args; }
+ const auto& getAttributes() const { return attrs; }
- bool hasFlag(unsigned i) const { return flags & i; }
+ bool hasAttribute(const FnAttrs::Attribute &i) const { return attrs.has(i); }
std::vector<Value*> operands() const override;
void rauw(const Value &what, Value &with) override;
void print(std::ostream &os) const override;

MODIFY
ir/state.cpp
ir/state.cpp
@@ -217,11 +217,14 @@ void State::addNoReturn() {
const vector<StateValue>
State::addFnCall(const string &name, vector<StateValue> &&inputs,
vector<pair<StateValue, bool>> &&ptr_inputs,
- const vector<Type*> &out_types, bool reads_memory,
- bool writes_memory, bool argmemonly) {
+ const vector<Type*> &out_types, const FnAttrs &attrs) {
// TODO: handle changes to memory due to fn call
// TODO: can read/write=false fn calls be removed?
+ bool reads_memory = !attrs.has(FnAttrs::NoRead);
+ bool writes_memory = !attrs.has(FnAttrs::NoWrite);
+ bool argmemonly = attrs.has(FnAttrs::ArgMemOnly);
+
expr all_args_np(true);
bool all_valid = true;
for (auto &v : inputs) {

MODIFY
ir/state.h
ir/state.h
@@ -142,8 +142,7 @@ public:
const std::vector<StateValue>
addFnCall(const std::string &name, std::vector<StateValue> &&inputs,
std::vector<std::pair<StateValue, bool>> &&ptr_inputs,
- const std::vector<Type*> &out_types, bool reads_memory,
- bool writes_memory, bool argmemonly);
+ const std::vector<Type*> &out_types, const FnAttrs &attrs);
void addQuantVar(const smt::expr &var);
void addUndefVar(smt::expr &&var);

MODIFY
llvm_util/llvm2alive.cpp
llvm_util/llvm2alive.cpp
@@ -249,24 +249,27 @@ public:
if (!ty)
return error(i);
- unsigned flags = 0;
+ FnAttrs attrs;
if (i.hasFnAttr(llvm::Attribute::ReadOnly))
- flags |= FnCall::NoWrite;
- if (i.hasFnAttr(llvm::Attribute::ReadNone))
- flags |= FnCall::NoRead | FnCall::NoWrite;
+ attrs.set(FnAttrs::NoWrite);
+ if (i.hasFnAttr(llvm::Attribute::ReadNone)) {
+ attrs.set(FnAttrs::NoRead);
+ attrs.set(FnAttrs::NoWrite);
+ }
if (i.hasFnAttr(llvm::Attribute::WriteOnly))
- flags |= FnCall::NoRead;
+ attrs.set(FnAttrs::NoRead);
if (i.hasFnAttr(llvm::Attribute::ArgMemOnly))
- flags |= FnCall::ArgMemOnly;
+ attrs.set(FnAttrs::ArgMemOnly);
if (i.hasFnAttr(llvm::Attribute::NoReturn))
- flags |= FnCall::NoReturn;
+ attrs.set(FnAttrs::NoReturn);
if (auto op = dyn_cast<llvm::FPMathOperator>(&i)) {
if (op->hasNoNaNs())
- flags |= FnCall::NNaN;
+ attrs.set(FnAttrs::NNaN);
}
string fn_name = '@' + fn->getName().str();
- auto call = make_unique<FnCall>(*ty, value_name(i), move(fn_name), flags,
+ auto call =
+ make_unique<FnCall>(*ty, value_name(i), move(fn_name), move(attrs),
!known);
unique_ptr<Instr> ret_val;
auto argI = fn->arg_begin(), argE = fn->arg_end();
@@ -279,7 +282,7 @@ public:
else if (argI->hasReturnedAttr()) {
auto call2
= make_unique<FnCall>(Type::voidTy, "", string(call->getFnName()),
- flags, !known);
+ FnAttrs(call->getAttributes()), !known);
for (auto &[arg, flags] : call->getArgs()) {
call2->addArg(*arg, ParamAttrs(flags));
}

Factor out FnAttrs class (#378)