From e7ebb87222e33936f6e5f3bd3fda919080ece1a0 Mon Sep 17 00:00:00 2001 From: Philip Reames Date: Thu, 25 Mar 2021 14:47:31 -0700 Subject: [PATCH] [deref] Handle byval/byref/sret/inalloc/preallocated arguments for deref-at-point semantics All of these are scoped allocations which remain dereferenceable during the lifetime of the callee. Differential Revision: https://reviews.llvm.org/D99310 --- llvm/lib/IR/Value.cpp | 6 +++++ .../ValueTracking/memory-dereferenceable.ll | 24 +++++++++---------- 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/llvm/lib/IR/Value.cpp b/llvm/lib/IR/Value.cpp index 8c06d4fe22d9..fb4eb9a9e3a6 100644 --- a/llvm/lib/IR/Value.cpp +++ b/llvm/lib/IR/Value.cpp @@ -739,6 +739,12 @@ static bool canBeFreed(const Value *V) { 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 index 1b66112db8bb..231fa83417c2 100644 --- a/llvm/test/Analysis/ValueTracking/memory-dereferenceable.ll +++ b/llvm/test/Analysis/ValueTracking/memory-dereferenceable.ll @@ -25,8 +25,7 @@ declare i32* @foo() ; 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 @@ define void @global_allocationsize() { ; 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 }