[llvm] e7ebb87 - [deref] Handle byval/byref/sret/inalloc/preallocated arguments for deref-at-point semantics

Philip Reames via llvm-commits llvm-commits at lists.llvm.org
Thu Mar 25 14:48:32 PDT 2021


Author: Philip Reames
Date: 2021-03-25T14:47:31-07:00
New Revision: e7ebb87222e33936f6e5f3bd3fda919080ece1a0

URL: https://github.com/llvm/llvm-project/commit/e7ebb87222e33936f6e5f3bd3fda919080ece1a0
DIFF: https://github.com/llvm/llvm-project/commit/e7ebb87222e33936f6e5f3bd3fda919080ece1a0.diff

LOG: [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

Added: 
    

Modified: 
    llvm/lib/IR/Value.cpp
    llvm/test/Analysis/ValueTracking/memory-dereferenceable.ll

Removed: 
    


################################################################################
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<Constant>(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<Argument>(V))
+    if (A->hasPointeeInMemoryValueAttr())
+      return false;
+
   const Function *F = nullptr;
   if (auto *I = dyn_cast<Instruction>(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
 }
 


        


More information about the llvm-commits mailing list