[llvm] 00e6869 - [MemCpyOpt] Look through pointer casts when checking capture

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Wed Jan 5 00:50:41 PST 2022


Author: Nikita Popov
Date: 2022-01-05T09:50:33+01:00
New Revision: 00e6869463ae6023d0d48f30de8511d6d748b14f

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

LOG: [MemCpyOpt] Look through pointer casts when checking capture

The user scanning loop above looks through pointer casts, so we
also need to strip pointer casts in the capture check. Previously
the source was incorrectly considered not captured if a bitcast
was passed to the call.

Added: 
    

Modified: 
    llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp
    llvm/test/Transforms/MemCpyOpt/callslot.ll
    llvm/test/Transforms/MemCpyOpt/capturing-func.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp b/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp
index d6723fffb18c0..13847406c25a0 100644
--- a/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp
+++ b/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp
@@ -949,7 +949,8 @@ bool MemCpyOptPass::performCallSlotOptzn(Instruction *cpyLoad,
   // Check whether src is captured by the called function, in which case there
   // may be further indirect uses of src.
   bool SrcIsCaptured = any_of(C->args(), [&](Use &U) {
-    return U == cpySrc && !C->doesNotCapture(C->getArgOperandNo(&U));
+    return U->stripPointerCasts() == cpySrc &&
+           !C->doesNotCapture(C->getArgOperandNo(&U));
   });
 
   // If src is captured, then check whether there are any potential uses of

diff  --git a/llvm/test/Transforms/MemCpyOpt/callslot.ll b/llvm/test/Transforms/MemCpyOpt/callslot.ll
index c118646669ea4..5cb57022198fa 100644
--- a/llvm/test/Transforms/MemCpyOpt/callslot.ll
+++ b/llvm/test/Transforms/MemCpyOpt/callslot.ll
@@ -172,7 +172,7 @@ define void @capture_before_call_argmemonly() {
 ; CHECK-NEXT:    [[SRC_I8:%.*]] = bitcast [16 x i8]* [[SRC]] to i8*
 ; CHECK-NEXT:    call void @accept_ptr(i8* [[DEST_I8]])
 ; CHECK-NEXT:    [[DEST1:%.*]] = bitcast [16 x i8]* [[DEST]] to i8*
-; CHECK-NEXT:    call void @accept_ptr(i8* [[DEST1]]) #[[ATTR4:[0-9]+]]
+; CHECK-NEXT:    call void @accept_ptr(i8* nocapture [[DEST1]]) #[[ATTR4:[0-9]+]]
 ; CHECK-NEXT:    ret void
 ;
   %dest = alloca [16 x i8]
@@ -180,7 +180,7 @@ define void @capture_before_call_argmemonly() {
   %dest.i8 = bitcast [16 x i8]* %dest to i8*
   %src.i8 = bitcast [16 x i8]* %src to i8*
   call void @accept_ptr(i8* %dest.i8) ; capture
-  call void @accept_ptr(i8* %src.i8) argmemonly
+  call void @accept_ptr(i8* nocapture %src.i8) argmemonly
   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dest.i8, i8* %src.i8, i64 16, i1 false)
   ret void
 }
@@ -193,7 +193,7 @@ define void @capture_before_call_argmemonly_nounwind() {
 ; CHECK-NEXT:    [[SRC_I8:%.*]] = bitcast [16 x i8]* [[SRC]] to i8*
 ; CHECK-NEXT:    call void @accept_ptr(i8* [[DEST_I8]])
 ; CHECK-NEXT:    [[DEST1:%.*]] = bitcast [16 x i8]* [[DEST]] to i8*
-; CHECK-NEXT:    call void @accept_ptr(i8* [[DEST1]]) #[[ATTR5:[0-9]+]]
+; CHECK-NEXT:    call void @accept_ptr(i8* nocapture [[DEST1]]) #[[ATTR5:[0-9]+]]
 ; CHECK-NEXT:    ret void
 ;
   %dest = alloca [16 x i8]
@@ -202,7 +202,7 @@ define void @capture_before_call_argmemonly_nounwind() {
   %src.i8 = bitcast [16 x i8]* %src to i8*
   call void @accept_ptr(i8* %dest.i8) ; capture
   ; NB: argmemonly currently implies willreturn.
-  call void @accept_ptr(i8* %src.i8) argmemonly nounwind
+  call void @accept_ptr(i8* nocapture %src.i8) argmemonly nounwind
   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dest.i8, i8* %src.i8, i64 16, i1 false)
   ret void
 }
@@ -215,7 +215,7 @@ define void @capture_before_call_argmemonly_nounwind_willreturn() {
 ; CHECK-NEXT:    [[SRC_I8:%.*]] = bitcast [16 x i8]* [[SRC]] to i8*
 ; CHECK-NEXT:    call void @accept_ptr(i8* [[DEST_I8]])
 ; CHECK-NEXT:    [[DEST1:%.*]] = bitcast [16 x i8]* [[DEST]] to i8*
-; CHECK-NEXT:    call void @accept_ptr(i8* [[DEST1]]) #[[ATTR6:[0-9]+]]
+; CHECK-NEXT:    call void @accept_ptr(i8* nocapture [[DEST1]]) #[[ATTR6:[0-9]+]]
 ; CHECK-NEXT:    ret void
 ;
   %dest = alloca [16 x i8]
@@ -223,7 +223,7 @@ define void @capture_before_call_argmemonly_nounwind_willreturn() {
   %dest.i8 = bitcast [16 x i8]* %dest to i8*
   %src.i8 = bitcast [16 x i8]* %src to i8*
   call void @accept_ptr(i8* %dest.i8) ; capture
-  call void @accept_ptr(i8* %src.i8) argmemonly nounwind willreturn
+  call void @accept_ptr(i8* nocapture %src.i8) argmemonly nounwind willreturn
   call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dest.i8, i8* %src.i8, i64 16, i1 false)
   ret void
 }

diff  --git a/llvm/test/Transforms/MemCpyOpt/capturing-func.ll b/llvm/test/Transforms/MemCpyOpt/capturing-func.ll
index 4099e3c09852c..84c1446ae0a4b 100644
--- a/llvm/test/Transforms/MemCpyOpt/capturing-func.ll
+++ b/llvm/test/Transforms/MemCpyOpt/capturing-func.ll
@@ -28,15 +28,14 @@ define void @test() {
 }
 
 ; Same as previous test, but with a bitcasted argument.
-; TODO: Call slot optimization should not be applied here.
 define void @test_bitcast() {
 ; CHECK-LABEL: define {{[^@]+}}@test_bitcast() {
 ; CHECK-NEXT:    [[PTR1:%.*]] = alloca [2 x i8], align 1
 ; CHECK-NEXT:    [[PTR2:%.*]] = alloca [2 x i8], align 1
 ; CHECK-NEXT:    [[PTR1_CAST:%.*]] = bitcast [2 x i8]* [[PTR1]] to i8*
 ; CHECK-NEXT:    [[PTR2_CAST:%.*]] = bitcast [2 x i8]* [[PTR2]] to i8*
-; CHECK-NEXT:    [[PTR11:%.*]] = bitcast [2 x i8]* [[PTR1]] to i8*
-; CHECK-NEXT:    call void @foo(i8* [[PTR11]])
+; CHECK-NEXT:    call void @foo(i8* [[PTR2_CAST]])
+; CHECK-NEXT:    call void @llvm.memcpy.p0i8.p0i8.i32(i8* [[PTR1_CAST]], i8* [[PTR2_CAST]], i32 2, i1 false)
 ; CHECK-NEXT:    call void @foo(i8* [[PTR1_CAST]])
 ; CHECK-NEXT:    ret void
 ;


        


More information about the llvm-commits mailing list