Revert "[InstCombine] Support gep nuw in icmp folds" (#118698)
[llvm-project.git] / llvm / test / Transforms / ObjCARC / allocas.ll
blob6fe2edf3e2dd489d3c428b4a2e6109877f5f95eb
1 ; RUN: opt -passes=objc-arc -S < %s | FileCheck %s
3 declare ptr @llvm.objc.retain(ptr)
4 declare ptr @llvm.objc.retainAutoreleasedReturnValue(ptr)
5 declare void @llvm.objc.release(ptr)
6 declare ptr @llvm.objc.autorelease(ptr)
7 declare ptr @llvm.objc.autoreleaseReturnValue(ptr)
8 declare void @llvm.objc.autoreleasePoolPop(ptr)
9 declare ptr @llvm.objc.autoreleasePoolPush()
10 declare ptr @llvm.objc.retainBlock(ptr)
12 declare ptr @objc_retainedObject(ptr)
13 declare ptr @objc_unretainedObject(ptr)
14 declare ptr @objc_unretainedPointer(ptr)
16 declare void @use_pointer(ptr)
17 declare void @callee()
18 declare void @callee_fnptr(ptr)
19 declare void @invokee()
20 declare ptr @returner()
21 declare ptr @returner1()
22 declare ptr @returner2()
23 declare void @bar(ptr)
24 declare void @use_alloca(ptr)
26 declare void @llvm.dbg.value(metadata, metadata, metadata)
28 declare ptr @objc_msgSend(ptr, ptr, ...)
31 ; In the presence of allocas, unconditionally remove retain/release pairs only
32 ; if they are known safe in both directions. This prevents matching up an inner
33 ; retain with the boundary guarding release in the following situation:
34
35 ; %A = alloca
36 ; retain(%x)
37 ; retain(%x) <--- Inner Retain
38 ; store %x, %A
39 ; %y = load %A
40 ; ... DO STUFF ...
41 ; release(%y)
42 ; release(%x) <--- Guarding Release
44 ; rdar://13750319
46 ; CHECK: define void @test1a(ptr %x)
47 ; CHECK: @llvm.objc.retain(ptr %x)
48 ; CHECK: @llvm.objc.retain(ptr %x)
49 ; CHECK: @llvm.objc.release(ptr %y)
50 ; CHECK: @llvm.objc.release(ptr %x)
51 ; CHECK: ret void
52 ; CHECK: }
53 define void @test1a(ptr %x) {
54 entry:
55   %A = alloca ptr
56   tail call ptr @llvm.objc.retain(ptr %x)
57   tail call ptr @llvm.objc.retain(ptr %x)
58   store ptr %x, ptr %A, align 8
59   %y = load ptr, ptr %A
60   call void @use_alloca(ptr %A)
61   call void @llvm.objc.release(ptr %y), !clang.imprecise_release !0
62   call void @use_pointer(ptr %x)
63   call void @llvm.objc.release(ptr %x), !clang.imprecise_release !0
64   ret void
67 ; CHECK: define void @test1b(ptr %x)
68 ; CHECK: @llvm.objc.retain(ptr %x)
69 ; CHECK: @llvm.objc.retain(ptr %x)
70 ; CHECK: @llvm.objc.release(ptr %y)
71 ; CHECK: @llvm.objc.release(ptr %x)
72 ; CHECK: ret void
73 ; CHECK: }
74 define void @test1b(ptr %x) {
75 entry:
76   %A = alloca ptr
77   tail call ptr @llvm.objc.retain(ptr %x)
78   tail call ptr @llvm.objc.retain(ptr %x)
79   store ptr %x, ptr %A, align 8
80   %y = load ptr, ptr %A
81   call void @use_alloca(ptr %A)
82   call void @llvm.objc.release(ptr %y), !clang.imprecise_release !0
83   call void @use_pointer(ptr %x)
84   call void @llvm.objc.release(ptr %x), !clang.imprecise_release !0
85   ret void
89 ; CHECK: define void @test1c(ptr %x)
90 ; CHECK: @llvm.objc.retain(ptr %x)
91 ; CHECK: @llvm.objc.retain(ptr %x)
92 ; CHECK: @llvm.objc.release(ptr %y)
93 ; CHECK: @llvm.objc.release(ptr %x)
94 ; CHECK: ret void
95 ; CHECK: }
96 define void @test1c(ptr %x) {
97 entry:
98   %A = alloca ptr, i32 3
99   %gep = getelementptr ptr, ptr %A, i32 2
100   tail call ptr @llvm.objc.retain(ptr %x)
101   tail call ptr @llvm.objc.retain(ptr %x)
102   store ptr %x, ptr %gep, align 8
103   %y = load ptr, ptr %gep
104   call void @use_alloca(ptr %A)
105   call void @llvm.objc.release(ptr %y), !clang.imprecise_release !0
106   call void @use_pointer(ptr %x)
107   call void @llvm.objc.release(ptr %x), !clang.imprecise_release !0
108   ret void
112 ; CHECK: define void @test1d(ptr %x, i1 %arg)
113 ; CHECK: @llvm.objc.retain(ptr %x)
114 ; CHECK: @llvm.objc.retain(ptr %x)
115 ; CHECK: @llvm.objc.release(ptr %y)
116 ; CHECK: @llvm.objc.release(ptr %x)
117 ; CHECK: ret void
118 ; CHECK: }
119 define void @test1d(ptr %x, i1 %arg) {
120 entry:
121   br i1 %arg, label %use_allocaA, label %use_allocaB
123 use_allocaA:
124   %allocaA = alloca ptr
125   br label %exit
127 use_allocaB:
128   %allocaB = alloca ptr
129   br label %exit
131 exit:
132   %A = phi ptr [ %allocaA, %use_allocaA ], [ %allocaB, %use_allocaB ]
133   tail call ptr @llvm.objc.retain(ptr %x)
134   tail call ptr @llvm.objc.retain(ptr %x)
135   store ptr %x, ptr %A, align 8
136   %y = load ptr, ptr %A
137   call void @use_alloca(ptr %A)
138   call void @llvm.objc.release(ptr %y), !clang.imprecise_release !0
139   call void @use_pointer(ptr %x)
140   call void @llvm.objc.release(ptr %x), !clang.imprecise_release !0
141   ret void
144 ; CHECK: define void @test1e(ptr %x, i1 %arg)
145 ; CHECK: @llvm.objc.retain(ptr %x)
146 ; CHECK: @llvm.objc.retain(ptr %x)
147 ; CHECK: @llvm.objc.release(ptr %y)
148 ; CHECK: @llvm.objc.release(ptr %x)
149 ; CHECK: ret void
150 ; CHECK: }
151 define void @test1e(ptr %x, i1 %arg) {
152 entry:
153   br i1 %arg, label %use_allocaA, label %use_allocaB
155 use_allocaA:
156   %allocaA = alloca ptr, i32 4
157   br label %exit
159 use_allocaB:
160   %allocaB = alloca ptr, i32 4
161   br label %exit
163 exit:
164   %A = phi ptr [ %allocaA, %use_allocaA ], [ %allocaB, %use_allocaB ]
165   %gep = getelementptr ptr, ptr %A, i32 2
166   tail call ptr @llvm.objc.retain(ptr %x)
167   tail call ptr @llvm.objc.retain(ptr %x)
168   store ptr %x, ptr %gep, align 8
169   %y = load ptr, ptr %gep
170   call void @use_alloca(ptr %A)
171   call void @llvm.objc.release(ptr %y), !clang.imprecise_release !0
172   call void @use_pointer(ptr %x)
173   call void @llvm.objc.release(ptr %x), !clang.imprecise_release !0
174   ret void
177 ; CHECK: define void @test1f(ptr %x)
178 ; CHECK: @llvm.objc.retain(ptr %x)
179 ; CHECK: @llvm.objc.retain(ptr %x)
180 ; CHECK: @llvm.objc.release(ptr %y)
181 ; CHECK: @llvm.objc.release(ptr %x)
182 ; CHECK: ret void
183 ; CHECK: }
184 define void @test1f(ptr %x) {
185 entry:
186   %allocaOne = alloca ptr
187   %allocaTwo = alloca ptr
188   %A = select i1 undef, ptr %allocaOne, ptr %allocaTwo
189   tail call ptr @llvm.objc.retain(ptr %x)
190   tail call ptr @llvm.objc.retain(ptr %x)
191   store ptr %x, ptr %A, align 8
192   %y = load ptr, ptr %A
193   call void @use_alloca(ptr %A)
194   call void @llvm.objc.release(ptr %y), !clang.imprecise_release !0
195   call void @use_pointer(ptr %x)
196   call void @llvm.objc.release(ptr %x), !clang.imprecise_release !0
197   ret void
200 ; Make sure that if a store is in a different basic block we handle known safe
201 ; conservatively.
204 ; CHECK: define void @test2a(ptr %x)
205 ; CHECK: @llvm.objc.retain(ptr %x)
206 ; CHECK: @llvm.objc.retain(ptr %x)
207 ; CHECK: @llvm.objc.release(ptr %y)
208 ; CHECK: @llvm.objc.release(ptr %x)
209 ; CHECK: ret void
210 ; CHECK: }
211 define void @test2a(ptr %x) {
212 entry:
213   %A = alloca ptr
214   store ptr %x, ptr %A, align 8
215   %y = load ptr, ptr %A
216   br label %bb1
218 bb1:
219   br label %bb2
221 bb2:
222   br label %bb3
224 bb3:
225   tail call ptr @llvm.objc.retain(ptr %x)
226   tail call ptr @llvm.objc.retain(ptr %x)
227   call void @use_alloca(ptr %A)
228   call void @llvm.objc.release(ptr %y), !clang.imprecise_release !0
229   call void @use_pointer(ptr %x)
230   call void @llvm.objc.release(ptr %x), !clang.imprecise_release !0
231   ret void
234 ; CHECK: define void @test2b(ptr %x)
235 ; CHECK: @llvm.objc.retain(ptr %x)
236 ; CHECK: @llvm.objc.retain(ptr %x)
237 ; CHECK: @llvm.objc.release(ptr %y)
238 ; CHECK: @llvm.objc.release(ptr %x)
239 ; CHECK: ret void
240 ; CHECK: }
241 define void @test2b(ptr %x) {
242 entry:
243   %A = alloca ptr
244   store ptr %x, ptr %A, align 8
245   %y = load ptr, ptr %A
246   br label %bb1
248 bb1:
249   br label %bb2
251 bb2:
252   br label %bb3
254 bb3:
255   tail call ptr @llvm.objc.retain(ptr %x)
256   tail call ptr @llvm.objc.retain(ptr %x)
257   call void @use_alloca(ptr %A)
258   call void @llvm.objc.release(ptr %y), !clang.imprecise_release !0
259   call void @use_pointer(ptr %x)
260   call void @llvm.objc.release(ptr %x), !clang.imprecise_release !0
261   ret void
264 ; CHECK: define void @test2c(ptr %x)
265 ; CHECK: @llvm.objc.retain(ptr %x)
266 ; CHECK: @llvm.objc.retain(ptr %x)
267 ; CHECK: @llvm.objc.release(ptr %y)
268 ; CHECK: @llvm.objc.release(ptr %x)
269 ; CHECK: ret void
270 ; CHECK: }
271 define void @test2c(ptr %x) {
272 entry:
273   %A = alloca ptr, i32 3
274   %gep1 = getelementptr ptr, ptr %A, i32 2
275   store ptr %x, ptr %gep1, align 8
276   %gep2 = getelementptr ptr, ptr %A, i32 2
277   %y = load ptr, ptr %gep2
278   tail call ptr @llvm.objc.retain(ptr %x)
279   br label %bb1
281 bb1:
282   br label %bb2
284 bb2:
285   br label %bb3
287 bb3:
288   tail call ptr @llvm.objc.retain(ptr %x)
289   call void @use_alloca(ptr %A)
290   call void @llvm.objc.release(ptr %y), !clang.imprecise_release !0
291   call void @use_pointer(ptr %x)
292   call void @llvm.objc.release(ptr %x), !clang.imprecise_release !0
293   ret void
296 ; CHECK: define void @test2d(ptr %x)
297 ; CHECK: @llvm.objc.retain(ptr %x)
298 ; CHECK: @llvm.objc.retain(ptr %x)
299 ; CHECK: @llvm.objc.release(ptr %y)
300 ; CHECK: @llvm.objc.release(ptr %x)
301 ; CHECK: ret void
302 ; CHECK: }
303 define void @test2d(ptr %x) {
304 entry:
305   tail call ptr @llvm.objc.retain(ptr %x)
306   br label %bb1
308 bb1:
309   %Abb1 = alloca ptr, i32 3
310   %gepbb11 = getelementptr ptr, ptr %Abb1, i32 2
311   store ptr %x, ptr %gepbb11, align 8
312   %gepbb12 = getelementptr ptr, ptr %Abb1, i32 2
313   %ybb1 = load ptr, ptr %gepbb12
314   br label %bb3
316 bb2:
317   %Abb2 = alloca ptr, i32 4
318   %gepbb21 = getelementptr ptr, ptr %Abb2, i32 2
319   store ptr %x, ptr %gepbb21, align 8
320   %gepbb22 = getelementptr ptr, ptr %Abb2, i32 2
321   %ybb2 = load ptr, ptr %gepbb22
322   br label %bb3
324 bb3:
325   %A = phi ptr [ %Abb1, %bb1 ], [ %Abb2, %bb2 ]
326   %y = phi ptr [ %ybb1, %bb1 ], [ %ybb2, %bb2 ]
327   tail call ptr @llvm.objc.retain(ptr %x)
328   call void @use_alloca(ptr %A)
329   call void @llvm.objc.release(ptr %y), !clang.imprecise_release !0
330   call void @use_pointer(ptr %x)
331   call void @llvm.objc.release(ptr %x), !clang.imprecise_release !0
332   ret void
335 ; Make sure in the presence of allocas, if we find a cfghazard we do not perform
336 ; code motion even if we are known safe. These two concepts are separate and
337 ; should be treated as such.
339 ; rdar://13949644
341 ; CHECK: define void @test3a() {
342 ; CHECK: entry:
343 ; CHECK:   @llvm.objc.retainAutoreleasedReturnValue
344 ; CHECK:   @llvm.objc.retain
345 ; CHECK:   @llvm.objc.retain
346 ; CHECK:   @llvm.objc.retain
347 ; CHECK:   @llvm.objc.retain
348 ; CHECK: arraydestroy.body:
349 ; CHECK:   @llvm.objc.release
350 ; CHECK-NOT: @llvm.objc.release
351 ; CHECK: arraydestroy.done:
352 ; CHECK-NOT: @llvm.objc.release
353 ; CHECK: arraydestroy.body1:
354 ; CHECK:   @llvm.objc.release
355 ; CHECK-NOT: @llvm.objc.release
356 ; CHECK: arraydestroy.done1:
357 ; CHECK: @llvm.objc.release
358 ; CHECK: ret void
359 ; CHECK: }
360 define void @test3a() {
361 entry:
362   %keys = alloca [2 x ptr], align 16
363   %objs = alloca [2 x ptr], align 16
364   
365   %call1 = call ptr @returner()
366   %tmp0 = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call1)
368   tail call ptr @llvm.objc.retain(ptr %call1)
369   store ptr %call1, ptr %objs, align 8
370   %objs.elt = getelementptr inbounds [2 x ptr], ptr %objs, i64 0, i64 1
371   tail call ptr @llvm.objc.retain(ptr %call1)
372   store ptr %call1, ptr %objs.elt
374   %call2 = call ptr @returner1()
375   %call3 = call ptr @returner2()
376   tail call ptr @llvm.objc.retain(ptr %call2)
377   store ptr %call2, ptr %keys, align 8
378   %keys.elt = getelementptr inbounds [2 x ptr], ptr %keys, i64 0, i64 1
379   tail call ptr @llvm.objc.retain(ptr %call3)
380   store ptr %call3, ptr %keys.elt  
381   
382   %gep = getelementptr inbounds [2 x ptr], ptr %objs, i64 0, i64 2
383   br label %arraydestroy.body
385 arraydestroy.body:
386   %arraydestroy.elementPast = phi ptr [ %gep, %entry ], [ %arraydestroy.element, %arraydestroy.body ]
387   %arraydestroy.element = getelementptr inbounds ptr, ptr %arraydestroy.elementPast, i64 -1
388   %destroy_tmp = load ptr, ptr %arraydestroy.element, align 8
389   call void @llvm.objc.release(ptr %destroy_tmp), !clang.imprecise_release !0
390   %arraydestroy.cmp = icmp eq ptr %arraydestroy.element, %objs
391   br i1 %arraydestroy.cmp, label %arraydestroy.done, label %arraydestroy.body
393 arraydestroy.done:
394   %gep1 = getelementptr inbounds [2 x ptr], ptr %keys, i64 0, i64 2
395   br label %arraydestroy.body1
397 arraydestroy.body1:
398   %arraydestroy.elementPast1 = phi ptr [ %gep1, %arraydestroy.done ], [ %arraydestroy.element1, %arraydestroy.body1 ]
399   %arraydestroy.element1 = getelementptr inbounds ptr, ptr %arraydestroy.elementPast1, i64 -1
400   %destroy_tmp1 = load ptr, ptr %arraydestroy.element1, align 8
401   call void @llvm.objc.release(ptr %destroy_tmp1), !clang.imprecise_release !0
402   %arraydestroy.cmp1 = icmp eq ptr %arraydestroy.element1, %keys
403   br i1 %arraydestroy.cmp1, label %arraydestroy.done1, label %arraydestroy.body1
405 arraydestroy.done1:
406   call void @llvm.objc.release(ptr %call1), !clang.imprecise_release !0
407   ret void
410 ; Make sure that even though we stop said code motion we still allow for
411 ; pointers to be removed if we are known safe in both directions.
413 ; rdar://13949644
415 ; CHECK: define void @test3b() {
416 ; CHECK: entry:
417 ; CHECK:   @llvm.objc.retainAutoreleasedReturnValue
418 ; CHECK:   @llvm.objc.retain
419 ; CHECK:   @llvm.objc.retain
420 ; CHECK:   @llvm.objc.retain
421 ; CHECK:   @llvm.objc.retain
422 ; CHECK: arraydestroy.body:
423 ; CHECK:   @llvm.objc.release
424 ; CHECK-NOT: @llvm.objc.release
425 ; CHECK: arraydestroy.done:
426 ; CHECK-NOT: @llvm.objc.release
427 ; CHECK: arraydestroy.body1:
428 ; CHECK:   @llvm.objc.release
429 ; CHECK-NOT: @llvm.objc.release
430 ; CHECK: arraydestroy.done1:
431 ; CHECK: @llvm.objc.release
432 ; CHECK: ret void
433 ; CHECK: }
434 define void @test3b() {
435 entry:
436   %keys = alloca [2 x ptr], align 16
437   %objs = alloca [2 x ptr], align 16
438   
439   %call1 = call ptr @returner()
440   %tmp0 = tail call ptr @llvm.objc.retainAutoreleasedReturnValue(ptr %call1)
441   %tmp1 = tail call ptr @llvm.objc.retain(ptr %call1)
443   tail call ptr @llvm.objc.retain(ptr %call1)
444   store ptr %call1, ptr %objs, align 8
445   %objs.elt = getelementptr inbounds [2 x ptr], ptr %objs, i64 0, i64 1
446   tail call ptr @llvm.objc.retain(ptr %call1)
447   store ptr %call1, ptr %objs.elt
449   %call2 = call ptr @returner1()
450   %call3 = call ptr @returner2()
451   tail call ptr @llvm.objc.retain(ptr %call2)
452   store ptr %call2, ptr %keys, align 8
453   %keys.elt = getelementptr inbounds [2 x ptr], ptr %keys, i64 0, i64 1
454   tail call ptr @llvm.objc.retain(ptr %call3)
455   store ptr %call3, ptr %keys.elt  
456   
457   %gep = getelementptr inbounds [2 x ptr], ptr %objs, i64 0, i64 2
458   br label %arraydestroy.body
460 arraydestroy.body:
461   %arraydestroy.elementPast = phi ptr [ %gep, %entry ], [ %arraydestroy.element, %arraydestroy.body ]
462   %arraydestroy.element = getelementptr inbounds ptr, ptr %arraydestroy.elementPast, i64 -1
463   %destroy_tmp = load ptr, ptr %arraydestroy.element, align 8
464   call void @llvm.objc.release(ptr %destroy_tmp), !clang.imprecise_release !0
465   %arraydestroy.cmp = icmp eq ptr %arraydestroy.element, %objs
466   br i1 %arraydestroy.cmp, label %arraydestroy.done, label %arraydestroy.body
468 arraydestroy.done:
469   %gep1 = getelementptr inbounds [2 x ptr], ptr %keys, i64 0, i64 2
470   br label %arraydestroy.body1
472 arraydestroy.body1:
473   %arraydestroy.elementPast1 = phi ptr [ %gep1, %arraydestroy.done ], [ %arraydestroy.element1, %arraydestroy.body1 ]
474   %arraydestroy.element1 = getelementptr inbounds ptr, ptr %arraydestroy.elementPast1, i64 -1
475   %destroy_tmp1 = load ptr, ptr %arraydestroy.element1, align 8
476   call void @llvm.objc.release(ptr %destroy_tmp1), !clang.imprecise_release !0
477   %arraydestroy.cmp1 = icmp eq ptr %arraydestroy.element1, %keys
478   br i1 %arraydestroy.cmp1, label %arraydestroy.done1, label %arraydestroy.body1
480 arraydestroy.done1:
481   call void @llvm.objc.release(ptr %call1), !clang.imprecise_release !0
482   call void @llvm.objc.release(ptr %call1), !clang.imprecise_release !0
483   ret void
486 !0 = !{}
488 declare i32 @__gxx_personality_v0(...)