Add returned attribute
MODIFY
ir/attrs.cpp
ir/attrs.cpp
@@ -24,6 +24,8 @@ ostream& operator<<(ostream &os, const ParamAttrs &attr) {
os << "noundef ";
if (attr.has(ParamAttrs::Align))
os << "align(" << attr.align << ") ";
+ if (attr.has(ParamAttrs::Returned))
+ os << "returned ";
return os;
}

MODIFY
ir/attrs.h
ir/attrs.h
@@ -13,7 +13,7 @@ class ParamAttrs final {
public:
enum Attribute { None = 0, NonNull = 1<<0, ByVal = 1<<1, NoCapture = 1<<2,
ReadOnly = 1<<3, ReadNone = 1<<4, Dereferenceable = 1<<5,
- NoUndef = 1<<6, Align = 1<<7 };
+ NoUndef = 1<<6, Align = 1<<7, Returned = 1<<8 };
ParamAttrs(unsigned bits = None) : bits(bits) {}

MODIFY
ir/function.h
ir/function.h
@@ -72,6 +72,9 @@ class Function final {
std::vector<std::unique_ptr<AggregateValue>> aggregates;
std::vector<std::unique_ptr<Value>> inputs;
+ // an input that has 'returned' attribute
+ Value *returned_input = nullptr;
+
FnAttrs attrs;
public:
@@ -125,6 +128,8 @@ public:
return inputs;
}
bool hasSameInputs(const Function &rhs) const;
+ Value *getReturnedInput() const { return returned_input; }
+ void setReturnedInput(Value *v) { returned_input = v; }
bool hasReturn() const;
unsigned bitsPointers() const { return bits_pointers; }

MODIFY
ir/instr.cpp
ir/instr.cpp
@@ -2270,6 +2270,16 @@ StateValue Return::toSMT(State &s) const {
if (attrs.has(FnAttrs::NoReturn))
s.addUB(expr(false));
+ if (auto *val_returned = s.getFn().getReturnedInput()) {
+ // LangRef states that return type must be valid operands for bitcasts,
+ // which cannot be aggregate type.
+ assert(!dynamic_cast<AggregateType *>(&val->getType()));
+ auto &[v_returned, np_returned] = s[*val_returned];
+
+ s.addUB(retval.non_poison == np_returned &&
+ retval.non_poison.implies(retval.value == v_returned));
+ }
+
s.addReturn(move(retval));
return {};
}

MODIFY
llvm_util/llvm2alive.cpp
llvm_util/llvm2alive.cpp
@@ -1030,6 +1030,10 @@ end:
attrs.set(ParamAttrs::NoUndef);
continue;
+ case llvm::Attribute::Returned:
+ attrs.set(ParamAttrs::Returned);
+ continue;
+
default:
errorAttr(attr);
return nullopt;
@@ -1064,6 +1068,12 @@ end:
return {};
auto val = make_unique<Input>(*ty, value_name(arg), move(*attrs));
add_identifier(arg, *val.get());
+
+ if (arg.hasReturnedAttr()) {
+ // Cache this to avoid linear lookup at return
+ assert(Fn.getReturnedInput() == nullptr);
+ Fn.setReturnedInput(val.get());
+ }
Fn.addInput(move(val));
}

ADD
tests/alive-tv/attrs/returned-2.srctgt.ll
+; An optimization that is done by GVN
+define i32 @src(i32 returned %x) {
+ %c = icmp eq i32 %x, 10
+ br i1 %c, label %A, label %B
+A:
+ ret i32 %x
+B:
+ ret i32 0
+}
+
+define i32 @tgt(i32 returned %x) {
+ %c = icmp eq i32 %x, 10
+ br i1 %c, label %A, label %B
+A:
+ ret i32 10
+B:
+ ret i32 0
+}

ADD
tests/alive-tv/attrs/returned-3.srctgt.ll
+define i32 @src(i32 returned %x) {
+ %c = icmp eq i32 %x, 10
+ br i1 %c, label %A, label %B
+A:
+ ret i32 11 ; UB
+B:
+ ret i32 0
+}
+
+define i32 @tgt(i32 returned %x) {
+ %c = icmp eq i32 %x, 10
+ br i1 %c, label %A, label %B
+A:
+ unreachable
+B:
+ ret i32 0
+}

Add returned attribute (#532)