diff --git a/llvm/lib/IR/Value.cpp b/llvm/lib/IR/Value.cpp --- a/llvm/lib/IR/Value.cpp +++ b/llvm/lib/IR/Value.cpp @@ -739,6 +739,12 @@ if (isa(V)) return false; + // Handle byval/byref/sret/inalloca/preallocated arguments. The storage + // lifetime is guaranteed to be longer than the callee's lifetime. + if (auto *A = dyn_cast(V)) + if (A->hasPointeeInMemoryValueAttr()) + return false; + const Function *F = nullptr; if (auto *I = dyn_cast(V)) F = I->getFunction(); diff --git a/llvm/test/Analysis/ValueTracking/memory-dereferenceable.ll b/llvm/test/Analysis/ValueTracking/memory-dereferenceable.ll --- a/llvm/test/Analysis/ValueTracking/memory-dereferenceable.ll +++ b/llvm/test/Analysis/ValueTracking/memory-dereferenceable.ll @@ -25,8 +25,7 @@ ; Loads from sret arguments ; CHECK-LABEL: 'test_sret' -; GLOBAL: %sret_gep{{.*}}(aligned) -; POINT-NOT: %sret_gep{{.*}}(aligned) +; CHECK: %sret_gep{{.*}}(aligned) ; CHECK-NOT: %sret_gep_outside define void @test_sret(%struct.A* sret(%struct.A) %result) { %sret_gep = getelementptr inbounds %struct.A, %struct.A* %result, i64 0, i32 1, i64 2 @@ -210,22 +209,23 @@ ; Loads from byval arguments ; CHECK-LABEL: 'byval' -; GLOBAL: %i8_byval{{.*}}(aligned) -; POINT-NOT: %i8_byval{{.*}}(aligned) -; CHECK-NOT: %byval_cast -; GLOBAL: %byval_gep{{.*}}(aligned) -; POINT-NOT: %byval_gep{{.*}}(aligned) -; FIXME: Should hold in the point semantics case too +; CHECK: %i8_byval{{.*}}(aligned) +; CHECK-NOT: %bad_byval_cast +; CHECK: %byval_gep{{.*}}(aligned) +; CHECK: %good_byval_cast{{.*}}(unaligned) define void @byval(i8* byval(i8) %i8_byval, - %struct.A* byval(%struct.A) %A_byval) { + %struct.A* byval(%struct.A) %A_byval) { call void @mayfree() - %i8_byval_load = load i8, i8* %i8_byval + load i8, i8* %i8_byval - %byval_cast = bitcast i8* %i8_byval to i32* - %bad_byval_load = load i32, i32* %byval_cast + %bad_byval_cast = bitcast i8* %i8_byval to i32* + load i32, i32* %bad_byval_cast %byval_gep = getelementptr inbounds %struct.A, %struct.A* %A_byval, i64 0, i32 1, i64 2 load i8, i8* %byval_gep + %good_byval_cast = bitcast %struct.A* %A_byval to i32* + load i32, i32* %good_byval_cast + ret void }