1c2e77c91SNikita Popov; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature 2*f3a928e2SArthur Eubanks; RUN: opt < %s -passes='require<globals-aa>,memcpyopt' -S -verify-memoryssa | FileCheck %s 3cee313d2SEric Christopher 4cee313d2SEric Christophertarget datalayout = "e" 5cee313d2SEric Christopher 642d98d80SNikita Popovdeclare void @foo(ptr) 742d98d80SNikita Popovdeclare void @llvm.memcpy.p0.p0.i32(ptr nocapture, ptr nocapture, i32, i1) nounwind 842d98d80SNikita Popovdeclare void @llvm.lifetime.start.p0(i64, ptr nocapture) 942d98d80SNikita Popovdeclare void @llvm.lifetime.end.p0(i64, ptr nocapture) 10cee313d2SEric Christopher 11396370e8SNikita Popov; Check that the transformation isn't applied if the called function can 12396370e8SNikita Popov; capture the pointer argument (i.e. the nocapture attribute isn't present) 13cee313d2SEric Christopherdefine void @test() { 14c2e77c91SNikita Popov; CHECK-LABEL: define {{[^@]+}}@test() { 1564c54c54SNikita Popov; CHECK-NEXT: [[PTR1:%.*]] = alloca i8, align 1 1664c54c54SNikita Popov; CHECK-NEXT: [[PTR2:%.*]] = alloca i8, align 1 1742d98d80SNikita Popov; CHECK-NEXT: call void @foo(ptr [[PTR2]]) 1842d98d80SNikita Popov; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr [[PTR1]], ptr [[PTR2]], i32 1, i1 false) 1942d98d80SNikita Popov; CHECK-NEXT: call void @foo(ptr [[PTR1]]) 2064c54c54SNikita Popov; CHECK-NEXT: ret void 2164c54c54SNikita Popov; 22cee313d2SEric Christopher %ptr1 = alloca i8 23cee313d2SEric Christopher %ptr2 = alloca i8 2442d98d80SNikita Popov call void @foo(ptr %ptr2) 2542d98d80SNikita Popov call void @llvm.memcpy.p0.p0.i32(ptr %ptr1, ptr %ptr2, i32 1, i1 false) 2642d98d80SNikita Popov call void @foo(ptr %ptr1) 27cee313d2SEric Christopher ret void 28396370e8SNikita Popov} 29cee313d2SEric Christopher 30396370e8SNikita Popov; Same as previous test, but with a bitcasted argument. 31396370e8SNikita Popovdefine void @test_bitcast() { 32c2e77c91SNikita Popov; CHECK-LABEL: define {{[^@]+}}@test_bitcast() { 33396370e8SNikita Popov; CHECK-NEXT: [[PTR1:%.*]] = alloca [2 x i8], align 1 34396370e8SNikita Popov; CHECK-NEXT: [[PTR2:%.*]] = alloca [2 x i8], align 1 3542d98d80SNikita Popov; CHECK-NEXT: call void @foo(ptr [[PTR2]]) 3642d98d80SNikita Popov; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr [[PTR1]], ptr [[PTR2]], i32 2, i1 false) 3742d98d80SNikita Popov; CHECK-NEXT: call void @foo(ptr [[PTR1]]) 38396370e8SNikita Popov; CHECK-NEXT: ret void 39396370e8SNikita Popov; 40396370e8SNikita Popov %ptr1 = alloca [2 x i8] 41396370e8SNikita Popov %ptr2 = alloca [2 x i8] 4242d98d80SNikita Popov call void @foo(ptr %ptr2) 4342d98d80SNikita Popov call void @llvm.memcpy.p0.p0.i32(ptr %ptr1, ptr %ptr2, i32 2, i1 false) 4442d98d80SNikita Popov call void @foo(ptr %ptr1) 45396370e8SNikita Popov ret void 46396370e8SNikita Popov} 47396370e8SNikita Popov 48396370e8SNikita Popov; Lifetime of %ptr2 ends before the potential use of the capture in the second 49396370e8SNikita Popov; call. 50396370e8SNikita Popovdefine void @test_lifetime_end() { 51c2e77c91SNikita Popov; CHECK-LABEL: define {{[^@]+}}@test_lifetime_end() { 52396370e8SNikita Popov; CHECK-NEXT: [[PTR1:%.*]] = alloca i8, align 1 53396370e8SNikita Popov; CHECK-NEXT: [[PTR2:%.*]] = alloca i8, align 1 5442d98d80SNikita Popov; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 1, ptr [[PTR2]]) 5542d98d80SNikita Popov; CHECK-NEXT: call void @foo(ptr [[PTR1]]) 5642d98d80SNikita Popov; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 1, ptr [[PTR2]]) 5742d98d80SNikita Popov; CHECK-NEXT: call void @foo(ptr [[PTR1]]) 58396370e8SNikita Popov; CHECK-NEXT: ret void 59396370e8SNikita Popov; 60396370e8SNikita Popov %ptr1 = alloca i8 61396370e8SNikita Popov %ptr2 = alloca i8 6242d98d80SNikita Popov call void @llvm.lifetime.start.p0(i64 1, ptr %ptr2) 6342d98d80SNikita Popov call void @foo(ptr %ptr2) 6442d98d80SNikita Popov call void @llvm.memcpy.p0.p0.i32(ptr %ptr1, ptr %ptr2, i32 1, i1 false) 6542d98d80SNikita Popov call void @llvm.lifetime.end.p0(i64 1, ptr %ptr2) 6642d98d80SNikita Popov call void @foo(ptr %ptr1) 67396370e8SNikita Popov ret void 68396370e8SNikita Popov} 69396370e8SNikita Popov 70c2e77c91SNikita Popov; Lifetime of %ptr2 does not end, because of size mismatch. 71c2e77c91SNikita Popovdefine void @test_lifetime_not_end() { 72c2e77c91SNikita Popov; CHECK-LABEL: define {{[^@]+}}@test_lifetime_not_end() { 73c2e77c91SNikita Popov; CHECK-NEXT: [[PTR1:%.*]] = alloca i8, align 1 74c2e77c91SNikita Popov; CHECK-NEXT: [[PTR2:%.*]] = alloca i8, align 1 7542d98d80SNikita Popov; CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 1, ptr [[PTR2]]) 7642d98d80SNikita Popov; CHECK-NEXT: call void @foo(ptr [[PTR2]]) 7742d98d80SNikita Popov; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr [[PTR1]], ptr [[PTR2]], i32 1, i1 false) 7842d98d80SNikita Popov; CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 0, ptr [[PTR2]]) 7942d98d80SNikita Popov; CHECK-NEXT: call void @foo(ptr [[PTR1]]) 80c2e77c91SNikita Popov; CHECK-NEXT: ret void 81c2e77c91SNikita Popov; 82c2e77c91SNikita Popov %ptr1 = alloca i8 83c2e77c91SNikita Popov %ptr2 = alloca i8 8442d98d80SNikita Popov call void @llvm.lifetime.start.p0(i64 1, ptr %ptr2) 8542d98d80SNikita Popov call void @foo(ptr %ptr2) 8642d98d80SNikita Popov call void @llvm.memcpy.p0.p0.i32(ptr %ptr1, ptr %ptr2, i32 1, i1 false) 8742d98d80SNikita Popov call void @llvm.lifetime.end.p0(i64 0, ptr %ptr2) 8842d98d80SNikita Popov call void @foo(ptr %ptr1) 89c2e77c91SNikita Popov ret void 90c2e77c91SNikita Popov} 91c2e77c91SNikita Popov 92396370e8SNikita Popov; Lifetime of %ptr2 ends before any potential use of the capture because we 93396370e8SNikita Popov; return from the function. 94396370e8SNikita Popovdefine void @test_function_end() { 95c2e77c91SNikita Popov; CHECK-LABEL: define {{[^@]+}}@test_function_end() { 96396370e8SNikita Popov; CHECK-NEXT: [[PTR1:%.*]] = alloca i8, align 1 97396370e8SNikita Popov; CHECK-NEXT: [[PTR2:%.*]] = alloca i8, align 1 9842d98d80SNikita Popov; CHECK-NEXT: call void @foo(ptr [[PTR1]]) 99396370e8SNikita Popov; CHECK-NEXT: ret void 100396370e8SNikita Popov; 101396370e8SNikita Popov %ptr1 = alloca i8 102396370e8SNikita Popov %ptr2 = alloca i8 10342d98d80SNikita Popov call void @foo(ptr %ptr2) 10442d98d80SNikita Popov call void @llvm.memcpy.p0.p0.i32(ptr %ptr1, ptr %ptr2, i32 1, i1 false) 105396370e8SNikita Popov ret void 106cee313d2SEric Christopher} 107c2e77c91SNikita Popov 108c2e77c91SNikita Popov; A potential use of the capture occurs in a later block, can't be optimized. 109c2e77c91SNikita Popovdefine void @test_terminator() { 110c2e77c91SNikita Popov; CHECK-LABEL: define {{[^@]+}}@test_terminator() { 111c2e77c91SNikita Popov; CHECK-NEXT: [[PTR1:%.*]] = alloca i8, align 1 112c2e77c91SNikita Popov; CHECK-NEXT: [[PTR2:%.*]] = alloca i8, align 1 11342d98d80SNikita Popov; CHECK-NEXT: call void @foo(ptr [[PTR2]]) 11442d98d80SNikita Popov; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr [[PTR1]], ptr [[PTR2]], i32 1, i1 false) 115c2e77c91SNikita Popov; CHECK-NEXT: br label [[NEXT:%.*]] 116c2e77c91SNikita Popov; CHECK: next: 11742d98d80SNikita Popov; CHECK-NEXT: call void @foo(ptr [[PTR1]]) 118c2e77c91SNikita Popov; CHECK-NEXT: ret void 119c2e77c91SNikita Popov; 120c2e77c91SNikita Popov %ptr1 = alloca i8 121c2e77c91SNikita Popov %ptr2 = alloca i8 12242d98d80SNikita Popov call void @foo(ptr %ptr2) 12342d98d80SNikita Popov call void @llvm.memcpy.p0.p0.i32(ptr %ptr1, ptr %ptr2, i32 1, i1 false) 124c2e77c91SNikita Popov br label %next 125c2e77c91SNikita Popov 126c2e77c91SNikita Popovnext: 12742d98d80SNikita Popov call void @foo(ptr %ptr1) 128c2e77c91SNikita Popov ret void 129c2e77c91SNikita Popov} 130c2e77c91SNikita Popov 131c2e77c91SNikita Popov; This case can be optimized, but would require a scan across multiple blocks 132c2e77c91SNikita Popov; and is currently not performed. 133c2e77c91SNikita Popovdefine void @test_terminator2() { 134c2e77c91SNikita Popov; CHECK-LABEL: define {{[^@]+}}@test_terminator2() { 135c2e77c91SNikita Popov; CHECK-NEXT: [[PTR1:%.*]] = alloca i8, align 1 136c2e77c91SNikita Popov; CHECK-NEXT: [[PTR2:%.*]] = alloca i8, align 1 13742d98d80SNikita Popov; CHECK-NEXT: call void @foo(ptr [[PTR2]]) 13842d98d80SNikita Popov; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr [[PTR1]], ptr [[PTR2]], i32 1, i1 false) 139c2e77c91SNikita Popov; CHECK-NEXT: br label [[NEXT:%.*]] 140c2e77c91SNikita Popov; CHECK: next: 141c2e77c91SNikita Popov; CHECK-NEXT: ret void 142c2e77c91SNikita Popov; 143c2e77c91SNikita Popov %ptr1 = alloca i8 144c2e77c91SNikita Popov %ptr2 = alloca i8 14542d98d80SNikita Popov call void @foo(ptr %ptr2) 14642d98d80SNikita Popov call void @llvm.memcpy.p0.p0.i32(ptr %ptr1, ptr %ptr2, i32 1, i1 false) 147c2e77c91SNikita Popov br label %next 148c2e77c91SNikita Popov 149c2e77c91SNikita Popovnext: 150c2e77c91SNikita Popov ret void 151c2e77c91SNikita Popov} 152c2e77c91SNikita Popov 15342d98d80SNikita Popovdeclare void @capture(ptr) 154c2e77c91SNikita Popov 155c2e77c91SNikita Popov; This case should not be optimized, because dest is captured before the call. 156c2e77c91SNikita Popovdefine void @test_dest_captured_before_alloca() { 157c2e77c91SNikita Popov; CHECK-LABEL: define {{[^@]+}}@test_dest_captured_before_alloca() { 158c2e77c91SNikita Popov; CHECK-NEXT: [[PTR1:%.*]] = alloca i8, align 1 159c2e77c91SNikita Popov; CHECK-NEXT: [[PTR2:%.*]] = alloca i8, align 1 16042d98d80SNikita Popov; CHECK-NEXT: call void @capture(ptr [[PTR1]]) 16142d98d80SNikita Popov; CHECK-NEXT: call void @foo(ptr [[PTR2]]) #[[ATTR2:[0-9]+]] 16242d98d80SNikita Popov; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr [[PTR1]], ptr [[PTR2]], i32 1, i1 false) 163c2e77c91SNikita Popov; CHECK-NEXT: ret void 164c2e77c91SNikita Popov; 165c2e77c91SNikita Popov %ptr1 = alloca i8 166c2e77c91SNikita Popov %ptr2 = alloca i8 16742d98d80SNikita Popov call void @capture(ptr %ptr1) 16842d98d80SNikita Popov call void @foo(ptr %ptr2) argmemonly 16942d98d80SNikita Popov call void @llvm.memcpy.p0.p0.i32(ptr %ptr1, ptr %ptr2, i32 1, i1 false) 170c2e77c91SNikita Popov ret void 171c2e77c91SNikita Popov} 172c2e77c91SNikita Popov 173c2e77c91SNikita Popov 174c2e77c91SNikita Popov@g = internal global i8 0 175c2e77c91SNikita Popov 176c2e77c91SNikita Popov; This case should not be optimized, because @g is captured before the call 177c2e77c91SNikita Popov; (being a global) and @icmp_g might depend on its identity. 178c2e77c91SNikita Popovdefine void @test_dest_captured_before_global() { 179c2e77c91SNikita Popov; CHECK-LABEL: define {{[^@]+}}@test_dest_captured_before_global() { 180c2e77c91SNikita Popov; CHECK-NEXT: [[PTR:%.*]] = alloca i8, align 1 18142d98d80SNikita Popov; CHECK-NEXT: call void @icmp_g(ptr [[PTR]]) 18242d98d80SNikita Popov; CHECK-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr @g, ptr [[PTR]], i32 1, i1 false) 183c2e77c91SNikita Popov; CHECK-NEXT: ret void 184c2e77c91SNikita Popov; 185c2e77c91SNikita Popov %ptr = alloca i8 18642d98d80SNikita Popov call void @icmp_g(ptr %ptr) 18742d98d80SNikita Popov call void @llvm.memcpy.p0.p0.i32(ptr @g, ptr %ptr, i32 1, i1 false) 188c2e77c91SNikita Popov ret void 189c2e77c91SNikita Popov} 190c2e77c91SNikita Popov 19142d98d80SNikita Popovdefine void @icmp_g(ptr %p) { 192c2e77c91SNikita Popov; CHECK-LABEL: define {{[^@]+}}@icmp_g 19342d98d80SNikita Popov; CHECK-SAME: (ptr [[P:%.*]]) { 19442d98d80SNikita Popov; CHECK-NEXT: [[C:%.*]] = icmp eq ptr [[P]], @g 195c2e77c91SNikita Popov; CHECK-NEXT: br i1 [[C]], label [[IF:%.*]], label [[ELSE:%.*]] 196c2e77c91SNikita Popov; CHECK: if: 19742d98d80SNikita Popov; CHECK-NEXT: store i8 1, ptr [[P]], align 1 198c2e77c91SNikita Popov; CHECK-NEXT: ret void 199c2e77c91SNikita Popov; CHECK: else: 20042d98d80SNikita Popov; CHECK-NEXT: store i8 2, ptr [[P]], align 1 201c2e77c91SNikita Popov; CHECK-NEXT: ret void 202c2e77c91SNikita Popov; 20342d98d80SNikita Popov %c = icmp eq ptr %p, @g 204c2e77c91SNikita Popov br i1 %c, label %if, label %else 205c2e77c91SNikita Popov 206c2e77c91SNikita Popovif: 20742d98d80SNikita Popov store i8 1, ptr %p 208c2e77c91SNikita Popov ret void 209c2e77c91SNikita Popov 210c2e77c91SNikita Popovelse: 21142d98d80SNikita Popov store i8 2, ptr %p 212c2e77c91SNikita Popov ret void 213c2e77c91SNikita Popov} 214