xref: /llvm-project/llvm/test/Transforms/MemCpyOpt/capturing-func.ll (revision f3a928e2334a4e8e3f09406f2ce7e1cbac520f95)
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