forked from OSchip/llvm-project
[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
This commit is contained in:
parent
67e28173f1
commit
e7ebb87222
|
@ -739,6 +739,12 @@ static bool canBeFreed(const Value *V) {
|
||||||
if (isa<Constant>(V))
|
if (isa<Constant>(V))
|
||||||
return false;
|
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<Argument>(V))
|
||||||
|
if (A->hasPointeeInMemoryValueAttr())
|
||||||
|
return false;
|
||||||
|
|
||||||
const Function *F = nullptr;
|
const Function *F = nullptr;
|
||||||
if (auto *I = dyn_cast<Instruction>(V))
|
if (auto *I = dyn_cast<Instruction>(V))
|
||||||
F = I->getFunction();
|
F = I->getFunction();
|
||||||
|
|
|
@ -25,8 +25,7 @@ declare i32* @foo()
|
||||||
|
|
||||||
; Loads from sret arguments
|
; Loads from sret arguments
|
||||||
; CHECK-LABEL: 'test_sret'
|
; CHECK-LABEL: 'test_sret'
|
||||||
; GLOBAL: %sret_gep{{.*}}(aligned)
|
; CHECK: %sret_gep{{.*}}(aligned)
|
||||||
; POINT-NOT: %sret_gep{{.*}}(aligned)
|
|
||||||
; CHECK-NOT: %sret_gep_outside
|
; CHECK-NOT: %sret_gep_outside
|
||||||
define void @test_sret(%struct.A* sret(%struct.A) %result) {
|
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
|
%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
|
; Loads from byval arguments
|
||||||
; CHECK-LABEL: 'byval'
|
; CHECK-LABEL: 'byval'
|
||||||
; GLOBAL: %i8_byval{{.*}}(aligned)
|
; CHECK: %i8_byval{{.*}}(aligned)
|
||||||
; POINT-NOT: %i8_byval{{.*}}(aligned)
|
; CHECK-NOT: %bad_byval_cast
|
||||||
; CHECK-NOT: %byval_cast
|
; CHECK: %byval_gep{{.*}}(aligned)
|
||||||
; GLOBAL: %byval_gep{{.*}}(aligned)
|
; CHECK: %good_byval_cast{{.*}}(unaligned)
|
||||||
; POINT-NOT: %byval_gep{{.*}}(aligned)
|
|
||||||
; FIXME: Should hold in the point semantics case too
|
|
||||||
define void @byval(i8* byval(i8) %i8_byval,
|
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()
|
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_cast = bitcast i8* %i8_byval to i32*
|
||||||
%bad_byval_load = load i32, i32* %byval_cast
|
load i32, i32* %bad_byval_cast
|
||||||
|
|
||||||
%byval_gep = getelementptr inbounds %struct.A, %struct.A* %A_byval, i64 0, i32 1, i64 2
|
%byval_gep = getelementptr inbounds %struct.A, %struct.A* %A_byval, i64 0, i32 1, i64 2
|
||||||
load i8, i8* %byval_gep
|
load i8, i8* %byval_gep
|
||||||
|
%good_byval_cast = bitcast %struct.A* %A_byval to i32*
|
||||||
|
load i32, i32* %good_byval_cast
|
||||||
|
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue