bug fixing for memory attribute
check fncall semantics such that attributes of the caller are not imposed on the callee
MODIFY
ir/attrs.cpp
ir/attrs.cpp
@@ -178,16 +178,6 @@ bool MemoryAccess::canWriteSomething() const {
return false;
}
-bool MemoryAccess::canReadWriteSame(bool skip_args) const {
- for (unsigned i = 0; i < NumTypes; ++i) {
- if (skip_args && i == Args)
- continue;
- if (canRead(AccessType(i)) && canWrite(AccessType(i)))
- return true;
- }
- return false;
-}
-
void MemoryAccess::setFullAccess() {
for (unsigned i = 0; i < NumTypes; ++i) {
setCanAlsoAccess(AccessType(i));
@@ -236,10 +226,6 @@ void MemoryAccess::setCanAlsoAccess(AccessType ty) {
setCanAlsoWrite(ty);
}
-bool MemoryAccess::refinedBy(MemoryAccess rhs) const {
- return (val & rhs.val) == rhs.val;
-}
-
ostream& operator<<(ostream &os, const MemoryAccess &a) {
if (a.val == 0)
return os << " memory(none)";
@@ -462,8 +448,10 @@ bool FnAttrs::refinedBy(const FnAttrs &other) const {
if ((bits & attrs) != (other.bits & attrs))
return false;
- return mem.refinedBy(other.mem) &&
- fp_denormal == other.fp_denormal &&
+ if (has(NoReturn) && other.has(WillReturn))
+ return false;
+
+ return fp_denormal == other.fp_denormal &&
fp_denormal32 == other.fp_denormal32;
}

MODIFY
ir/attrs.h
ir/attrs.h
@@ -33,7 +33,6 @@ public:
bool canWriteAnything() const;
bool canReadSomething() const;
bool canWriteSomething() const;
- bool canReadWriteSame(bool skip_args) const;
void setNoAccess() { val = 0; }
void setFullAccess();
@@ -51,8 +50,6 @@ public:
void operator|=(MemoryAccess rhs) { val |= rhs.val; }
MemoryAccess operator|(MemoryAccess rhs) const { return val | rhs.val; }
- bool refinedBy(MemoryAccess rhs) const;
-
auto operator<=>(const MemoryAccess &rhs) const = default;
friend std::ostream& operator<<(std::ostream &os, const MemoryAccess &a);
};

MODIFY
ir/instr.cpp
ir/instr.cpp
@@ -2159,7 +2159,7 @@ static void check_can_load(State &s, const expr &p0) {
(attrs.mem.canRead(MemoryAccess::Args) ? readable : nonreadable)
|= ptr_only_args(s, p);
- s.addUB(readable & !nonreadable);
+ s.addUB(readable && !nonreadable);
}
static void check_can_store(State &s, const expr &p0) {
@@ -2177,7 +2177,7 @@ static void check_can_store(State &s, const expr &p0) {
(attrs.mem.canWrite(MemoryAccess::Args) ? writable : nonwritable)
|= ptr_only_args(s, p);
- s.addUB(writable & !nonwritable);
+ s.addUB(writable && !nonwritable);
}
static void unpack_inputs(State &s, Value &argv, Type &ty,
@@ -2282,14 +2282,8 @@ StateValue FnCall::toSMT(State &s) const {
if (!isVoid())
unpack_ret_ty(out_types, getType());
- auto check = [&](FnAttrs::Attribute attr) {
- return s.getFn().getFnAttrs().has(attr) && !hasAttribute(attr);
- };
-
// Check attributes that calles must have if caller has them
- if (check(FnAttrs::NoThrow) ||
- check(FnAttrs::WillReturn) ||
- !attrs.mem.refinedBy(s.getFn().getFnAttrs().mem))
+ if (!attrs.refinedBy(s.getFn().getFnAttrs()))
s.addUB(expr(false));
auto get_alloc_ptr = [&]() -> Value& {
@@ -2355,22 +2349,6 @@ StateValue FnCall::toSMT(State &s) const {
return {};
}
- // fn has nofree but callsite hasn't
- if (check(FnAttrs::NoFree)) {
- if (attrs.mem.canWrite(MemoryAccess::Other)) {
- s.addUB(expr(false));
- }
- if (attrs.mem.canWrite(MemoryAccess::Args)) {
- for (auto &p : ptr_inputs) {
- if (!p.byval) {
- Pointer ptr(m, p.val.value);
- s.addUB(p.val.non_poison.implies(
- ptr.isLocal() || ptr.isConstGlobal()));
- }
- }
- }
- }
-
unsigned idx = 0;
auto ret = s.addFnCall(fnName_mangled.str(), std::move(inputs),
std::move(ptr_inputs), out_types, attrs);

MODIFY
ir/state.cpp
ir/state.cpp
@@ -59,6 +59,9 @@ void State::ValueAnalysis::meet_with(const State::ValueAnalysis &other) {
void State::ValueAnalysis::FnCallRanges::inc(const string &name,
MemoryAccess access) {
+ if (!access.canWriteSomething())
+ return;
+
auto [I, inserted] = try_emplace(name);
if (inserted) {
I->second.first.emplace(1);
@@ -74,10 +77,37 @@ void State::ValueAnalysis::FnCallRanges::inc(const string &name,
}
bool
-State::ValueAnalysis::FnCallRanges::overlaps(const FnCallRanges &other) const {
+State::ValueAnalysis::FnCallRanges::overlaps(const string &callee,
+ MemoryAccess call_access,
+ const FnCallRanges &other) const {
+ if (!call_access.canReadSomething())
+ return true;
+
+ auto skip = [call_access, &callee](const auto &fn, MemoryAccess access) {
+ if (access.canOnlyWrite(MemoryAccess::Inaccessible)) {
+ // If this fn can only write to inaccessible memory, ignore if it's not
+ // our callee as callee can't read from that memory
+ if (fn != callee)
+ return true;
+
+ // If the trace only writes to inaccessible memory, but the callee can't
+ // read it, any mismatch in the number of calls is irrelevant
+ if (!call_access.canRead(MemoryAccess::Inaccessible))
+ return true;
+ }
+
+ if (call_access.canOnlyRead(MemoryAccess::Inaccessible) && fn == callee) {
+ if (!access.canWrite(MemoryAccess::Inaccessible))
+ return true;
+ }
+ return false;
+ };
+
for (auto &[fn, pair] : *this) {
auto &[calls, access] = pair;
- if (access.canOnlyWrite(MemoryAccess::Args))
+ assert(access.canWriteSomething());
+
+ if (skip(fn, access))
continue;
auto I = other.find(fn);
@@ -86,7 +116,10 @@ State::ValueAnalysis::FnCallRanges::overlaps(const FnCallRanges &other) const {
continue;
return false;
}
- if (!(access | I->second.second).canReadWriteSame(/*skip_args=*/true))
+
+ // A function that doesn't read anything, may write the same thing on
+ // every call. So a mismatch in the number of calls must be ignored.
+ if (!(access | I->second.second).canReadSomething())
continue;
if (intersect_set(calls, I->second.first).empty())
@@ -95,7 +128,7 @@ State::ValueAnalysis::FnCallRanges::overlaps(const FnCallRanges &other) const {
for (auto &[fn, pair] : other) {
auto &[calls, access] = pair;
- if (access.canOnlyWrite(MemoryAccess::Args))
+ if (skip(fn, access))
continue;
if (!calls.count(0) && !count(fn))
@@ -709,7 +742,8 @@ expr State::FnCallInput::operator==(const FnCallInput &rhs) const {
}
expr State::FnCallInput::refinedBy(
- State &s, unsigned inaccessible_bid, const vector<StateValue> &args_nonptr2,
+ State &s, const string &callee, unsigned inaccessible_bid,
+ const vector<StateValue> &args_nonptr2,
const vector<Memory::PtrInput> &args_ptr2,
const ValueAnalysis::FnCallRanges &fncall_ranges2,
const Memory &m2, MemoryAccess memaccess2, bool noret2, bool willret2) const {
@@ -717,7 +751,7 @@ expr State::FnCallInput::refinedBy(
if (memaccess != memaccess2 ||
noret != noret2 ||
willret != willret2 ||
- (memaccess.canReadSomething() && !fncall_ranges.overlaps(fncall_ranges2)))
+ !fncall_ranges.overlaps(callee, memaccess2, fncall_ranges2))
return false;
AndExpr refines;
@@ -916,9 +950,9 @@ State::addFnCall(const string &name, vector<StateValue> &&inputs,
ChoiceExpr<FnCallOutput> data;
for (auto &[in, out] : fn_call_data[name]) {
- auto refined = in.refinedBy(*this, inaccessible_bid, inputs, ptr_inputs,
- call_ranges, memory, attrs.mem, noret,
- willret);
+ auto refined = in.refinedBy(*this, name, inaccessible_bid, inputs,
+ ptr_inputs, call_ranges, memory, attrs.mem,
+ noret, willret);
data.add(out, std::move(refined));
}
@@ -958,7 +992,6 @@ State::addFnCall(const string &name, vector<StateValue> &&inputs,
}
}
- if (attrs.mem.canWriteSomething())
analysis.ranges_fn_calls.inc(name, attrs.mem);
return retval;

MODIFY
ir/state.h
ir/state.h
@@ -59,7 +59,8 @@ private:
: public std::map<std::string, std::pair<std::set<unsigned>,
MemoryAccess>> {
void inc(const std::string &name, MemoryAccess access);
- bool overlaps(const FnCallRanges &other) const;
+ bool overlaps(const std::string &callee, MemoryAccess call_access,
+ const FnCallRanges &other) const;
// remove all ranges but name
FnCallRanges project(const std::string &name) const;
};
@@ -157,7 +158,8 @@ private:
bool noret, willret;
smt::expr operator==(const FnCallInput &rhs) const;
- smt::expr refinedBy(State &s, unsigned inaccessible_bid,
+ smt::expr refinedBy(State &s, const std::string &callee,
+ unsigned inaccessible_bid,
const std::vector<StateValue> &args_nonptr,
const std::vector<Memory::PtrInput> &args_ptr,
const ValueAnalysis::FnCallRanges &fncall_ranges,

MODIFY
llvm_util/llvm2alive.cpp
llvm_util/llvm2alive.cpp
@@ -1083,7 +1083,6 @@ public:
case llvm::Intrinsic::sideeffect: {
FnAttrs attrs;
parse_fn_attrs(i, attrs);
- attrs.mem.setCanOnlyAccess(MemoryAccess::Inaccessible);
attrs.set(FnAttrs::WillReturn);
attrs.set(FnAttrs::NoThrow);
return

MODIFY
tests/alive-tv/attrs/argmemonly-poison.srctgt.ll
tests/alive-tv/attrs/argmemonly-poison.srctgt.ll
+; ERROR: Source is more defined than target
+
@glb = external global i8
define void @src(ptr %p) memory(argmem: readwrite) {

MODIFY
tests/alive-tv/attrs/argmemonly-ub.srctgt.ll
tests/alive-tv/attrs/argmemonly-ub.srctgt.ll
+; ERROR: Source is more defined than target
+
@glb = external global i8
-define void @src(i8 *%p) memory(argmem: readwrite) {
+define void @src(ptr %p) memory(argmem: readwrite) {
call void @f(ptr %p)
ret void
}
-define void @tgt(i8 *%p) memory(argmem: readwrite) {
+define void @tgt(ptr %p) memory(argmem: readwrite) {
unreachable
}

MODIFY
tests/alive-tv/attrs/argmemonly.srctgt.ll
tests/alive-tv/attrs/argmemonly.srctgt.ll
-define i8 @src(i8 *%p) memory(argmem: readwrite) {
+define i8 @src(ptr %p) memory(argmem: readwrite) {
%p2 = getelementptr i8, ptr %p, i32 0
%v = call i8 @f(ptr %p2)
ret i8 %v
}
-define i8 @tgt(i8 *%p) memory(argmem: readwrite) {
+define i8 @tgt(ptr %p) memory(argmem: readwrite) {
%v = call i8 @f(ptr %p)
ret i8 %v
}

MODIFY
tests/alive-tv/attrs/nofree2.srctgt.ll
tests/alive-tv/attrs/nofree2.srctgt.ll
+; ERROR: Source is more defined than target
+
define void @src() nofree {
call void @fn()
ret void

MODIFY
tests/alive-tv/bugs/pr29034.src.ll
tests/alive-tv/bugs/pr29034.src.ll
target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
target triple = "aarch64"
-%struct._MUSIC_OP_API_ = type { %struct._FILE_OPERATE_*, %struct.__MUSIC_API* }
-%struct._FILE_OPERATE_ = type { %struct._FILE_OPERATE_INIT_*, %struct._lg_dev_info_* }
-%struct._FILE_OPERATE_INIT_ = type { i32, i32, i32, i32, ptr, ptr, i32 }
-%struct._lg_dev_info_ = type { %struct.os_event, i32, i32, %struct._lg_dev_hdl_*, i8, i8, i8, i8, i8 }
-%struct.os_event = type { i8, i32, ptr, %union.anon }
-%union.anon = type { %struct.event_cnt }
-%struct.event_cnt = type { i16 }
-%struct._lg_dev_hdl_ = type { ptr, ptr, ptr, ptr, ptr }
-%struct.__MUSIC_API = type <{ ptr, ptr, i32, %struct._DEC_API, %struct._DEC_API_IO*, %struct._FS_BRK_POINT* }>
-%struct._DEC_API = type { %struct._DEC_PHY*, ptr, ptr, ptr (ptr)*, ptr (ptr)*, ptr, %struct._AAC_DEFAULT_SETTING, i32, i32, ptr, %struct.decoder_inf*, i32, i8, ptr, i8, ptr }
-%struct._DEC_PHY = type { ptr, %struct.__audio_decoder_ops*, ptr, %struct.if_decoder_io, %struct.if_dec_file*, ptr, i32 (ptr)*, i32, i8, %struct.__FF_FR }
-%struct.__audio_decoder_ops = type { ptr, i32 (ptr, %struct.if_decoder_io*, ptr)*, i32 (ptr)*, i32 (ptr, i32)*, %struct.decoder_inf* (ptr)*, i32 (ptr)*, i32 (ptr)*, i32 (...)*, i32 (...)*, i32 (...)*, void (ptr, i32)*, void (ptr, i32, ptr, i32)*, i32 (ptr, i32, ptr)* }
-%struct.if_decoder_io = type { ptr, i32 (ptr, i32, ptr, i32, i8)*, i32 (ptr, i32, ptr)*, void (ptr, ptr, i32)*, i32 (ptr)*, i32 (ptr, i32, i32)* }
-%struct.if_dec_file = type { i32 (ptr, ptr, i32)*, i32 (ptr, i32, i32)* }
-%struct.__FF_FR = type { i32, i32, i8, i8, i8 }
+%struct._MUSIC_OP_API_ = type {ptr, ptr }
+%struct.__MUSIC_API = type <{ ptr, ptr, i32, %struct._DEC_API, ptr, ptr }>
+%struct._DEC_API = type { ptr, ptr, ptr, ptr, ptr, ptr, %struct._AAC_DEFAULT_SETTING, i32, i32, ptr, ptr, i32, i8, ptr, i8, ptr }
%struct._AAC_DEFAULT_SETTING = type { i32, i32, i32 }
-%struct.decoder_inf = type { i16, i16, i32, i32 }
-%struct._DEC_API_IO = type { ptr, ptr, i16 (ptr, ptr, i16)*, i32 (ptr, i8, i32)*, i32 (%struct.decoder_inf*, i32)*, %struct.__OP_IO, i32, i32 }
-%struct.__OP_IO = type { ptr, ptr (ptr, ptr, i32)* }
-%struct._FS_BRK_POINT = type { %struct._FS_BRK_INFO, i32, i32 }
-%struct._FS_BRK_INFO = type { i32, i32, [8 x i8], i8, i8, i16 }
@.str = external hidden unnamed_addr constant [10 x i8], align 1
-; Function Attrs: minsize noreturn nounwind optsize
-define void @music_task(ptr nocapture readnone %p) local_unnamed_addr #0 {
+define void @music_task(ptr nocapture readnone %p) #0 {
entry:
- %mapi = alloca %struct._MUSIC_OP_API_*, align 8
- %0 = bitcast %struct._MUSIC_OP_API_** %mapi to ptr
- call void @llvm.lifetime.start(i64 8, ptr %0) #4
- store %struct._MUSIC_OP_API_* null, %struct._MUSIC_OP_API_** %mapi, align 8
- %call = call i32 @music_decoder_init(%struct._MUSIC_OP_API_** nonnull %mapi) #4
+ %mapi = alloca ptr, align 8
+ %0 = bitcast ptr %mapi to ptr
+ call void @llvm.lifetime.start(i64 8, ptr %0) #3
+ store ptr null, ptr %mapi, align 8
+ %call = call i32 @music_decoder_init(ptr nonnull %mapi) #3
br label %while.cond
while.cond.loopexit: ; preds = %while.cond2
br label %while.cond
while.cond: ; preds = %while.cond.loopexit, %entry
- %1 = load %struct._MUSIC_OP_API_*, %struct._MUSIC_OP_API_** %mapi, align 8
- %dop_api = getelementptr inbounds %struct._MUSIC_OP_API_, %struct._MUSIC_OP_API_* %1, i64 0, i32 1
- %2 = load %struct.__MUSIC_API*, %struct.__MUSIC_API** %dop_api, align 8
- %file_num = getelementptr inbounds %struct.__MUSIC_API, %struct.__MUSIC_API* %2, i64 0, i32 2
+ %1 = load ptr, ptr %mapi, align 8
+ %dop_api = getelementptr inbounds %struct._MUSIC_OP_API_, ptr %1, i64 0, i32 1
+ %2 = load ptr, ptr %dop_api, align 8
+ %file_num = getelementptr inbounds %struct.__MUSIC_API, ptr %2, i64 0, i32 2
%3 = bitcast ptr %file_num to ptr
- %call1 = call i32 @music_play_api(%struct._MUSIC_OP_API_* %1, i32 33, i32 0, i32 28, ptr %3) #4
+ %call1 = call i32 @music_play_api(ptr %1, i32 33, i32 0, i32 28, ptr %3) #3
br label %while.cond2
while.cond2: ; preds = %while.cond2.backedge, %while.cond
@@ -62,37 +44,37 @@ while.cond2: ; preds = %while.cond2.backedg
]
sw.bb: ; preds = %while.cond2
- %4 = load %struct._MUSIC_OP_API_*, %struct._MUSIC_OP_API_** %mapi, align 8
- %dop_api4 = getelementptr inbounds %struct._MUSIC_OP_API_, %struct._MUSIC_OP_API_* %4, i64 0, i32 1
- %5 = load %struct.__MUSIC_API*, %struct.__MUSIC_API** %dop_api4, align 8
- %file_num5 = getelementptr inbounds %struct.__MUSIC_API, %struct.__MUSIC_API* %5, i64 0, i32 2
+ %4 = load ptr, ptr %mapi, align 8
+ %dop_api4 = getelementptr inbounds %struct._MUSIC_OP_API_, ptr %4, i64 0, i32 1
+ %5 = load ptr, ptr %dop_api4, align 8
+ %file_num5 = getelementptr inbounds %struct.__MUSIC_API, ptr %5, i64 0, i32 2
%6 = load i32, ptr %file_num5, align 1
%call6 = call i32 (ptr, ...) @printf(ptr getelementptr inbounds ([10 x i8], [10 x i8]* @.str, i64 0, i64 0), i32 %6) #6
br label %while.cond2.backedge
sw.bb7: ; preds = %while.cond2
- %7 = load %struct._MUSIC_OP_API_*, %struct._MUSIC_OP_API_** %mapi, align 8
- %dop_api8 = getelementptr inbounds %struct._MUSIC_OP_API_, %struct._MUSIC_OP_API_* %7, i64 0, i32 1
- %8 = load %struct.__MUSIC_API*, %struct.__MUSIC_API** %dop_api8, align 8
- %file_num9 = getelementptr inbounds %struct.__MUSIC_API, %struct.__MUSIC_API* %8, i64 0, i32 2
+ %7 = load ptr, ptr %mapi, align 8
+ %dop_api8 = getelementptr inbounds %struct._MUSIC_OP_API_, ptr %7, i64 0, i32 1
+ %8 = load ptr, ptr %dop_api8, align 8
+ %file_num9 = getelementptr inbounds %struct.__MUSIC_API, ptr %8, i64 0, i32 2
store i32 1, ptr %file_num9, align 1
%9 = bitcast ptr %file_num9 to ptr
- %call12 = call i32 @music_play_api(%struct._MUSIC_OP_API_* %7, i32 34, i32 0, i32 24, ptr %9) #4
+ %call12 = call i32 @music_play_api(ptr %7, i32 34, i32 0, i32 24, ptr %9) #3
br label %while.cond2.backedge
sw.bb13: ; preds = %while.cond2
- %10 = load %struct._MUSIC_OP_API_*, %struct._MUSIC_OP_API_** %mapi, align 8
- %dop_api14 = getelementptr inbounds %struct._MUSIC_OP_API_, %struct._MUSIC_OP_API_* %10, i64 0, i32 1
- %11 = load %struct.__MUSIC_API*, %struct.__MUSIC_API** %dop_api14, align 8
- %file_num15 = getelementptr inbounds %struct.__MUSIC_API, %struct.__MUSIC_API* %11, i64 0, i32 2
+ %10 = load ptr, ptr %mapi, align 8
+ %dop_api14 = getelementptr inbounds %struct._MUSIC_OP_API_, ptr %10, i64 0, i32 1
+ %11 = load ptr, ptr %dop_api14, align 8
+ %file_num15 = getelementptr inbounds %struct.__MUSIC_API, ptr %11, i64 0, i32 2
store i32 1, ptr %file_num15, align 1
%12 = bitcast ptr %file_num15 to ptr
- %call18 = call i32 @music_play_api(%struct._MUSIC_OP_API_* %10, i32 35, i32 0, i32 26, ptr %12) #4
+ %call18 = call i32 @music_play_api(ptr %10, i32 35, i32 0, i32 26, ptr %12) #3
br label %while.cond2.backedge
sw.default: ; preds = %while.cond2
- %13 = load %struct._MUSIC_OP_API_*, %struct._MUSIC_OP_API_** %mapi, align 8
- %call19 = call i32 @music_play_api(%struct._MUSIC_OP_API_* %13, i32 33, i32 0, i32 22, ptr null) #4
+ %13 = load ptr, ptr %mapi, align 8
+ %call19 = call i32 @music_play_api(ptr %13, i32 33, i32 0, i32 22, ptr null) #3
br label %while.cond2.backedge
while.cond2.backedge: ; preds = %sw.default, %sw.bb13, %sw.bb7, %sw.bb
@@ -101,12 +83,10 @@ while.cond2.backedge: ; preds = %sw.default, %sw.bb1
}
declare void @llvm.lifetime.start(i64, ptr nocapture) #1
-declare i32 @music_decoder_init(%struct._MUSIC_OP_API_**) local_unnamed_addr #2
-declare i32 @music_play_api(%struct._MUSIC_OP_API_*, i32, i32, i32, ptr) local_unnamed_addr #2
-declare i32 @printf(ptr nocapture readonly, ...) local_unnamed_addr #3
+declare i32 @music_decoder_init(ptr)
+declare i32 @music_play_api(ptr, i32, i32, i32, ptr)
+declare i32 @printf(ptr nocapture readonly, ...) #3
-attributes #0 = { noreturn nounwind optsize "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-signed-zeros-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #0 = { noreturn nounwind }
attributes #1 = { memory(argmem: readwrite) nounwind }
-attributes #2 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+neon" "unsafe-fp-math"="false" "use-soft-float"="false" }
-attributes #3 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+neon" "unsafe-fp-math"="false" "use-soft-float"="false" }
-attributes #4 = { nounwind }
+attributes #3 = { nounwind }

MODIFY
tests/alive-tv/bugs/pr29034.tgt.ll
tests/alive-tv/bugs/pr29034.tgt.ll
target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
target triple = "aarch64"
-%struct._MUSIC_OP_API_ = type { %struct._FILE_OPERATE_*, %struct.__MUSIC_API* }
-%struct._FILE_OPERATE_ = type { %struct._FILE_OPERATE_INIT_*, %struct._lg_dev_info_* }
-%struct._FILE_OPERATE_INIT_ = type { i32, i32, i32, i32, ptr, ptr, i32 }
-%struct._lg_dev_info_ = type { %struct.os_event, i32, i32, %struct._lg_dev_hdl_*, i8, i8, i8, i8, i8 }
-%struct.os_event = type { i8, i32, ptr, %union.anon }
-%union.anon = type { %struct.event_cnt }
-%struct.event_cnt = type { i16 }
-%struct._lg_dev_hdl_ = type { ptr, ptr, ptr, ptr, ptr }
-%struct.__MUSIC_API = type <{ ptr, ptr, i32, %struct._DEC_API, %struct._DEC_API_IO*, %struct._FS_BRK_POINT* }>
-%struct._DEC_API = type { %struct._DEC_PHY*, ptr, ptr, ptr (ptr)*, ptr (ptr)*, ptr, %struct._AAC_DEFAULT_SETTING, i32, i32, ptr, %struct.decoder_inf*, i32, i8, ptr, i8, ptr }
-%struct._DEC_PHY = type { ptr, %struct.__audio_decoder_ops*, ptr, %struct.if_decoder_io, %struct.if_dec_file*, ptr, i32 (ptr)*, i32, i8, %struct.__FF_FR }
-%struct.__audio_decoder_ops = type { ptr, i32 (ptr, %struct.if_decoder_io*, ptr)*, i32 (ptr)*, i32 (ptr, i32)*, %struct.decoder_inf* (ptr)*, i32 (ptr)*, i32 (ptr)*, i32 (...)*, i32 (...)*, i32 (...)*, void (ptr, i32)*, void (ptr, i32, ptr, i32)*, i32 (ptr, i32, ptr)* }
-%struct.if_decoder_io = type { ptr, i32 (ptr, i32, ptr, i32, i8)*, i32 (ptr, i32, ptr)*, void (ptr, ptr, i32)*, i32 (ptr)*, i32 (ptr, i32, i32)* }
-%struct.if_dec_file = type { i32 (ptr, ptr, i32)*, i32 (ptr, i32, i32)* }
-%struct.__FF_FR = type { i32, i32, i8, i8, i8 }
+%struct._MUSIC_OP_API_ = type {ptr, ptr }
+%struct.__MUSIC_API = type <{ ptr, ptr, i32, %struct._DEC_API, ptr, ptr }>
+%struct._DEC_API = type { ptr, ptr, ptr, ptr, ptr, ptr, %struct._AAC_DEFAULT_SETTING, i32, i32, ptr, ptr, i32, i8, ptr, i8, ptr }
%struct._AAC_DEFAULT_SETTING = type { i32, i32, i32 }
-%struct.decoder_inf = type { i16, i16, i32, i32 }
-%struct._DEC_API_IO = type { ptr, ptr, i16 (ptr, ptr, i16)*, i32 (ptr, i8, i32)*, i32 (%struct.decoder_inf*, i32)*, %struct.__OP_IO, i32, i32 }
-%struct.__OP_IO = type { ptr, ptr (ptr, ptr, i32)* }
-%struct._FS_BRK_POINT = type { %struct._FS_BRK_INFO, i32, i32 }
-%struct._FS_BRK_INFO = type { i32, i32, [8 x i8], i8, i8, i16 }
@.str = external hidden unnamed_addr constant [10 x i8], align 1
-; Function Attrs: minsize noreturn nounwind optsize
-define void @music_task(ptr nocapture readnone %p) local_unnamed_addr #0 {
+define void @music_task(ptr nocapture readnone %p) #0 {
entry:
- %mapi = alloca %struct._MUSIC_OP_API_*, align 8
- %0 = bitcast %struct._MUSIC_OP_API_** %mapi to ptr
- call void @llvm.lifetime.start(i64 8, ptr %0) #4
- store %struct._MUSIC_OP_API_* null, %struct._MUSIC_OP_API_** %mapi, align 8
- %call = call i32 @music_decoder_init(%struct._MUSIC_OP_API_** nonnull %mapi) #4
+ %mapi = alloca ptr, align 8
+ %0 = bitcast ptr %mapi to ptr
+ call void @llvm.lifetime.start(i64 8, ptr %0) #3
+ store ptr null, ptr %mapi, align 8
+ %call = call i32 @music_decoder_init(ptr nonnull %mapi) #3
br label %while.cond
while.cond.loopexit: ; preds = %while.cond2
br label %while.cond
while.cond: ; preds = %while.cond.loopexit, %entry
- %1 = load %struct._MUSIC_OP_API_*, %struct._MUSIC_OP_API_** %mapi, align 8
- %dop_api = getelementptr inbounds %struct._MUSIC_OP_API_, %struct._MUSIC_OP_API_* %1, i64 0, i32 1
- %2 = load %struct.__MUSIC_API*, %struct.__MUSIC_API** %dop_api, align 8
- %file_num = getelementptr inbounds %struct.__MUSIC_API, %struct.__MUSIC_API* %2, i64 0, i32 2
+ %1 = load ptr, ptr %mapi, align 8
+ %dop_api = getelementptr inbounds %struct._MUSIC_OP_API_, ptr %1, i64 0, i32 1
+ %2 = load ptr, ptr %dop_api, align 8
+ %file_num = getelementptr inbounds %struct.__MUSIC_API, ptr %2, i64 0, i32 2
%3 = bitcast ptr %file_num to ptr
- %call1 = call i32 @music_play_api(%struct._MUSIC_OP_API_* %1, i32 33, i32 0, i32 28, ptr %3) #4
+ %call1 = call i32 @music_play_api(ptr %1, i32 33, i32 0, i32 28, ptr %3) #3
br label %while.cond2
while.cond2: ; preds = %while.cond2.backedge, %while.cond
%err.0 = phi i32 [ %call1, %while.cond ], [ %err.0.be, %while.cond2.backedge ]
- %4 = load %struct._MUSIC_OP_API_*, %struct._MUSIC_OP_API_** %mapi, align 8
- %dop_api8 = getelementptr inbounds %struct._MUSIC_OP_API_, %struct._MUSIC_OP_API_* %4, i64 0, i32 1
- %5 = load %struct.__MUSIC_API*, %struct.__MUSIC_API** %dop_api8, align 8
- %file_num9 = getelementptr inbounds %struct.__MUSIC_API, %struct.__MUSIC_API* %5, i64 0, i32 2
+ %4 = load ptr, ptr %mapi, align 8
+ %dop_api8 = getelementptr inbounds %struct._MUSIC_OP_API_, ptr %4, i64 0, i32 1
+ %5 = load ptr, ptr %dop_api8, align 8
+ %file_num9 = getelementptr inbounds %struct.__MUSIC_API, ptr %5, i64 0, i32 2
%6 = bitcast ptr %file_num9 to ptr
store i32 1, ptr %file_num9, align 1
switch i32 %err.0, label %sw.default [
@@ -68,15 +50,15 @@ sw.bb: ; preds = %while.cond2
br label %while.cond2.backedge
sw.bb7: ; preds = %while.cond2
- %call12 = call i32 @music_play_api(%struct._MUSIC_OP_API_* %4, i32 34, i32 0, i32 24, ptr %6) #4
+ %call12 = call i32 @music_play_api(ptr %4, i32 34, i32 0, i32 24, ptr %6) #3
br label %while.cond2.backedge
sw.bb13: ; preds = %while.cond2
- %call18 = call i32 @music_play_api(%struct._MUSIC_OP_API_* %4, i32 35, i32 0, i32 26, ptr %6) #4
+ %call18 = call i32 @music_play_api(ptr %4, i32 35, i32 0, i32 26, ptr %6) #3
br label %while.cond2.backedge
sw.default: ; preds = %while.cond2
- %call19 = call i32 @music_play_api(%struct._MUSIC_OP_API_* %4, i32 33, i32 0, i32 22, ptr null) #4
+ %call19 = call i32 @music_play_api(ptr %4, i32 33, i32 0, i32 22, ptr null) #3
br label %while.cond2.backedge
while.cond2.backedge: ; preds = %sw.default, %sw.bb13, %sw.bb7, %sw.bb
@@ -85,12 +67,10 @@ while.cond2.backedge: ; preds = %sw.default, %sw.bb1
}
declare void @llvm.lifetime.start(i64, ptr nocapture) #1
-declare i32 @music_decoder_init(%struct._MUSIC_OP_API_**) local_unnamed_addr #2
-declare i32 @music_play_api(%struct._MUSIC_OP_API_*, i32, i32, i32, ptr) local_unnamed_addr #2
-declare i32 @printf(ptr nocapture readonly, ...) local_unnamed_addr #3
+declare i32 @music_decoder_init(ptr)
+declare i32 @music_play_api(ptr, i32, i32, i32, ptr)
+declare i32 @printf(ptr nocapture readonly, ...) #3
-attributes #0 = { noreturn nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+neon" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #0 = { noreturn nounwind }
attributes #1 = { memory(argmem: readwrite) nounwind }
-attributes #2 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+neon" "unsafe-fp-math"="false" "use-soft-float"="false" }
-attributes #3 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "target-features"="+neon" "unsafe-fp-math"="false" "use-soft-float"="false" }
-attributes #4 = { nounwind }
+attributes #3 = { nounwind }

MODIFY
tests/alive-tv/memory/inaccessiblememonly.srctgt.ll
tests/alive-tv/memory/inaccessiblememonly.srctgt.ll
+; ERROR: Source is more defined than target
+
define i4 @src() memory(inaccessiblemem: readwrite) {
call void @fn()
ret i4 0

MODIFY
tests/alive-tv/por/issue697_3.srctgt.ll
tests/alive-tv/por/issue697_3.srctgt.ll
@@ -10,7 +10,7 @@ if.then:
br label %if.end
if.end:
- %q = load ptr, ptr* @glb, align 8
+ %q = load ptr, ptr @glb, align 8
ret void
}

bug fixing for memory attribute
check fncall semantics such that attributes of the caller are not imposed on the callee