Skip to content

Commit e7ebb87

Browse files
committed
[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
1 parent 67e2817 commit e7ebb87

File tree

2 files changed

+18
-12
lines changed

2 files changed

+18
-12
lines changed

llvm/lib/IR/Value.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -739,6 +739,12 @@ static bool canBeFreed(const Value *V) {
739739
if (isa<Constant>(V))
740740
return false;
741741

742+
// Handle byval/byref/sret/inalloca/preallocated arguments. The storage
743+
// lifetime is guaranteed to be longer than the callee's lifetime.
744+
if (auto *A = dyn_cast<Argument>(V))
745+
if (A->hasPointeeInMemoryValueAttr())
746+
return false;
747+
742748
const Function *F = nullptr;
743749
if (auto *I = dyn_cast<Instruction>(V))
744750
F = I->getFunction();

llvm/test/Analysis/ValueTracking/memory-dereferenceable.ll

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@ declare i32* @foo()
2525

2626
; Loads from sret arguments
2727
; CHECK-LABEL: 'test_sret'
28-
; GLOBAL: %sret_gep{{.*}}(aligned)
29-
; POINT-NOT: %sret_gep{{.*}}(aligned)
28+
; CHECK: %sret_gep{{.*}}(aligned)
3029
; CHECK-NOT: %sret_gep_outside
3130
define void @test_sret(%struct.A* sret(%struct.A) %result) {
3231
%sret_gep = getelementptr inbounds %struct.A, %struct.A* %result, i64 0, i32 1, i64 2
@@ -210,22 +209,23 @@ define void @global_allocationsize() {
210209

211210
; Loads from byval arguments
212211
; CHECK-LABEL: 'byval'
213-
; GLOBAL: %i8_byval{{.*}}(aligned)
214-
; POINT-NOT: %i8_byval{{.*}}(aligned)
215-
; CHECK-NOT: %byval_cast
216-
; GLOBAL: %byval_gep{{.*}}(aligned)
217-
; POINT-NOT: %byval_gep{{.*}}(aligned)
218-
; FIXME: Should hold in the point semantics case too
212+
; CHECK: %i8_byval{{.*}}(aligned)
213+
; CHECK-NOT: %bad_byval_cast
214+
; CHECK: %byval_gep{{.*}}(aligned)
215+
; CHECK: %good_byval_cast{{.*}}(unaligned)
219216
define void @byval(i8* byval(i8) %i8_byval,
220-
%struct.A* byval(%struct.A) %A_byval) {
217+
%struct.A* byval(%struct.A) %A_byval) {
221218
call void @mayfree()
222-
%i8_byval_load = load i8, i8* %i8_byval
219+
load i8, i8* %i8_byval
223220

224-
%byval_cast = bitcast i8* %i8_byval to i32*
225-
%bad_byval_load = load i32, i32* %byval_cast
221+
%bad_byval_cast = bitcast i8* %i8_byval to i32*
222+
load i32, i32* %bad_byval_cast
226223

227224
%byval_gep = getelementptr inbounds %struct.A, %struct.A* %A_byval, i64 0, i32 1, i64 2
228225
load i8, i8* %byval_gep
226+
%good_byval_cast = bitcast %struct.A* %A_byval to i32*
227+
load i32, i32* %good_byval_cast
228+
229229
ret void
230230
}
231231

0 commit comments

Comments
 (0)