Follow up to d0858bffa11, add missing REQUIRES x86
[llvm-project.git] / llvm / test / Transforms / MemCpyOpt / capturing-func.ll
blob627dca5ab673f07b40d0abacac2831cb9867f4ce
1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature
2 ; RUN: opt < %s -passes='require<globals-aa>,memcpyopt' -S -verify-memoryssa | FileCheck %s
4 target datalayout = "e"
6 declare void @foo(ptr)
7 declare void @llvm.memcpy.p0.p0.i32(ptr nocapture, ptr nocapture, i32, i1) nounwind
8 declare void @llvm.lifetime.start.p0(i64, ptr nocapture)
9 declare void @llvm.lifetime.end.p0(i64, ptr nocapture)
11 ; Check that the transformation isn't applied if the called function can
12 ; capture the pointer argument (i.e. the nocapture attribute isn't present)
13 define void @test() {
14 ; CHECK-LABEL: define {{[^@]+}}@test() {
15 ; CHECK-NEXT:    [[PTR1:%.*]] = alloca i8, align 1
16 ; CHECK-NEXT:    [[PTR2:%.*]] = alloca i8, align 1
17 ; CHECK-NEXT:    call void @foo(ptr [[PTR2]])
18 ; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr [[PTR1]], ptr [[PTR2]], i32 1, i1 false)
19 ; CHECK-NEXT:    call void @foo(ptr [[PTR1]])
20 ; CHECK-NEXT:    ret void
22   %ptr1 = alloca i8
23   %ptr2 = alloca i8
24   call void @foo(ptr %ptr2)
25   call void @llvm.memcpy.p0.p0.i32(ptr %ptr1, ptr %ptr2, i32 1, i1 false)
26   call void @foo(ptr %ptr1)
27   ret void
30 ; Same as previous test, but with a bitcasted argument.
31 define void @test_bitcast() {
32 ; CHECK-LABEL: define {{[^@]+}}@test_bitcast() {
33 ; CHECK-NEXT:    [[PTR1:%.*]] = alloca [2 x i8], align 1
34 ; CHECK-NEXT:    [[PTR2:%.*]] = alloca [2 x i8], align 1
35 ; CHECK-NEXT:    call void @foo(ptr [[PTR2]])
36 ; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr [[PTR1]], ptr [[PTR2]], i32 2, i1 false)
37 ; CHECK-NEXT:    call void @foo(ptr [[PTR1]])
38 ; CHECK-NEXT:    ret void
40   %ptr1 = alloca [2 x i8]
41   %ptr2 = alloca [2 x i8]
42   call void @foo(ptr %ptr2)
43   call void @llvm.memcpy.p0.p0.i32(ptr %ptr1, ptr %ptr2, i32 2, i1 false)
44   call void @foo(ptr %ptr1)
45   ret void
48 ; Lifetime of %ptr2 ends before the potential use of the capture in the second
49 ; call.
50 define void @test_lifetime_end() {
51 ; CHECK-LABEL: define {{[^@]+}}@test_lifetime_end() {
52 ; CHECK-NEXT:    [[PTR1:%.*]] = alloca i8, align 1
53 ; CHECK-NEXT:    [[PTR2:%.*]] = alloca i8, align 1
54 ; CHECK-NEXT:    call void @llvm.lifetime.start.p0(i64 1, ptr [[PTR2]])
55 ; CHECK-NEXT:    call void @foo(ptr [[PTR1]])
56 ; CHECK-NEXT:    call void @llvm.lifetime.end.p0(i64 1, ptr [[PTR2]])
57 ; CHECK-NEXT:    call void @foo(ptr [[PTR1]])
58 ; CHECK-NEXT:    ret void
60   %ptr1 = alloca i8
61   %ptr2 = alloca i8
62   call void @llvm.lifetime.start.p0(i64 1, ptr %ptr2)
63   call void @foo(ptr %ptr2)
64   call void @llvm.memcpy.p0.p0.i32(ptr %ptr1, ptr %ptr2, i32 1, i1 false)
65   call void @llvm.lifetime.end.p0(i64 1, ptr %ptr2)
66   call void @foo(ptr %ptr1)
67   ret void
70 ; Lifetime of %ptr2 does not end, because of size mismatch.
71 define void @test_lifetime_not_end() {
72 ; CHECK-LABEL: define {{[^@]+}}@test_lifetime_not_end() {
73 ; CHECK-NEXT:    [[PTR1:%.*]] = alloca i8, align 1
74 ; CHECK-NEXT:    [[PTR2:%.*]] = alloca i8, align 1
75 ; CHECK-NEXT:    call void @llvm.lifetime.start.p0(i64 1, ptr [[PTR2]])
76 ; CHECK-NEXT:    call void @foo(ptr [[PTR2]])
77 ; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr [[PTR1]], ptr [[PTR2]], i32 1, i1 false)
78 ; CHECK-NEXT:    call void @llvm.lifetime.end.p0(i64 0, ptr [[PTR2]])
79 ; CHECK-NEXT:    call void @foo(ptr [[PTR1]])
80 ; CHECK-NEXT:    ret void
82   %ptr1 = alloca i8
83   %ptr2 = alloca i8
84   call void @llvm.lifetime.start.p0(i64 1, ptr %ptr2)
85   call void @foo(ptr %ptr2)
86   call void @llvm.memcpy.p0.p0.i32(ptr %ptr1, ptr %ptr2, i32 1, i1 false)
87   call void @llvm.lifetime.end.p0(i64 0, ptr %ptr2)
88   call void @foo(ptr %ptr1)
89   ret void
92 ; Lifetime of %ptr2 ends before any potential use of the capture because we
93 ; return from the function.
94 define void @test_function_end() {
95 ; CHECK-LABEL: define {{[^@]+}}@test_function_end() {
96 ; CHECK-NEXT:    [[PTR1:%.*]] = alloca i8, align 1
97 ; CHECK-NEXT:    [[PTR2:%.*]] = alloca i8, align 1
98 ; CHECK-NEXT:    call void @foo(ptr [[PTR1]])
99 ; CHECK-NEXT:    ret void
101   %ptr1 = alloca i8
102   %ptr2 = alloca i8
103   call void @foo(ptr %ptr2)
104   call void @llvm.memcpy.p0.p0.i32(ptr %ptr1, ptr %ptr2, i32 1, i1 false)
105   ret void
108 ; A potential use of the capture occurs in a later block, can't be optimized.
109 define void @test_terminator() {
110 ; CHECK-LABEL: define {{[^@]+}}@test_terminator() {
111 ; CHECK-NEXT:    [[PTR1:%.*]] = alloca i8, align 1
112 ; CHECK-NEXT:    [[PTR2:%.*]] = alloca i8, align 1
113 ; CHECK-NEXT:    call void @foo(ptr [[PTR2]])
114 ; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr [[PTR1]], ptr [[PTR2]], i32 1, i1 false)
115 ; CHECK-NEXT:    br label [[NEXT:%.*]]
116 ; CHECK:       next:
117 ; CHECK-NEXT:    call void @foo(ptr [[PTR1]])
118 ; CHECK-NEXT:    ret void
120   %ptr1 = alloca i8
121   %ptr2 = alloca i8
122   call void @foo(ptr %ptr2)
123   call void @llvm.memcpy.p0.p0.i32(ptr %ptr1, ptr %ptr2, i32 1, i1 false)
124   br label %next
126 next:
127   call void @foo(ptr %ptr1)
128   ret void
131 ; This case can be optimized, but would require a scan across multiple blocks
132 ; and is currently not performed.
133 define void @test_terminator2() {
134 ; CHECK-LABEL: define {{[^@]+}}@test_terminator2() {
135 ; CHECK-NEXT:    [[PTR1:%.*]] = alloca i8, align 1
136 ; CHECK-NEXT:    [[PTR2:%.*]] = alloca i8, align 1
137 ; CHECK-NEXT:    call void @foo(ptr [[PTR2]])
138 ; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr [[PTR1]], ptr [[PTR2]], i32 1, i1 false)
139 ; CHECK-NEXT:    br label [[NEXT:%.*]]
140 ; CHECK:       next:
141 ; CHECK-NEXT:    ret void
143   %ptr1 = alloca i8
144   %ptr2 = alloca i8
145   call void @foo(ptr %ptr2)
146   call void @llvm.memcpy.p0.p0.i32(ptr %ptr1, ptr %ptr2, i32 1, i1 false)
147   br label %next
149 next:
150   ret void
153 declare void @capture(ptr)
155 ; This case should not be optimized, because dest is captured before the call.
156 define void @test_dest_captured_before_alloca() {
157 ; CHECK-LABEL: define {{[^@]+}}@test_dest_captured_before_alloca() {
158 ; CHECK-NEXT:    [[PTR1:%.*]] = alloca i8, align 1
159 ; CHECK-NEXT:    [[PTR2:%.*]] = alloca i8, align 1
160 ; CHECK-NEXT:    call void @capture(ptr [[PTR1]])
161 ; CHECK-NEXT:    call void @foo(ptr [[PTR2]]) #[[ATTR2:[0-9]+]]
162 ; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr [[PTR1]], ptr [[PTR2]], i32 1, i1 false)
163 ; CHECK-NEXT:    ret void
165   %ptr1 = alloca i8
166   %ptr2 = alloca i8
167   call void @capture(ptr %ptr1)
168   call void @foo(ptr %ptr2) argmemonly
169   call void @llvm.memcpy.p0.p0.i32(ptr %ptr1, ptr %ptr2, i32 1, i1 false)
170   ret void
174 @g = internal global i8 0
176 ; This case should not be optimized, because @g is captured before the call
177 ; (being a global) and @icmp_g might depend on its identity.
178 define void @test_dest_captured_before_global() {
179 ; CHECK-LABEL: define {{[^@]+}}@test_dest_captured_before_global() {
180 ; CHECK-NEXT:    [[PTR:%.*]] = alloca i8, align 1
181 ; CHECK-NEXT:    call void @icmp_g(ptr [[PTR]])
182 ; CHECK-NEXT:    call void @llvm.memcpy.p0.p0.i32(ptr @g, ptr [[PTR]], i32 1, i1 false)
183 ; CHECK-NEXT:    ret void
185   %ptr = alloca i8
186   call void @icmp_g(ptr %ptr)
187   call void @llvm.memcpy.p0.p0.i32(ptr @g, ptr %ptr, i32 1, i1 false)
188   ret void
191 define void @icmp_g(ptr %p) {
192 ; CHECK-LABEL: define {{[^@]+}}@icmp_g
193 ; CHECK-SAME: (ptr [[P:%.*]]) {
194 ; CHECK-NEXT:    [[C:%.*]] = icmp eq ptr [[P]], @g
195 ; CHECK-NEXT:    br i1 [[C]], label [[IF:%.*]], label [[ELSE:%.*]]
196 ; CHECK:       if:
197 ; CHECK-NEXT:    store i8 1, ptr [[P]], align 1
198 ; CHECK-NEXT:    ret void
199 ; CHECK:       else:
200 ; CHECK-NEXT:    store i8 2, ptr [[P]], align 1
201 ; CHECK-NEXT:    ret void
203   %c = icmp eq ptr %p, @g
204   br i1 %c, label %if, label %else
207   store i8 1, ptr %p
208   ret void
210 else:
211   store i8 2, ptr %p
212   ret void