[clang][modules] Don't prevent translation of FW_Private includes when explicitly...
[llvm-project.git] / llvm / test / Transforms / DeadStoreElimination / multiblock-captures.ll
blob355b939a06592c11e7a9b942366f28bafbd24572
1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt < %s -passes=dse -S | FileCheck %s
4 target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
6 declare noalias ptr @malloc(i64)
8 declare void @foo()
9 declare void @capture(ptr)
11 ; Check that we do not remove the second store, as %m is returned.
12 define ptr @test_return_captures_1() {
13 ; CHECK-LABEL: @test_return_captures_1(
14 ; CHECK-NEXT:    [[M:%.*]] = call ptr @malloc(i64 24)
15 ; CHECK-NEXT:    store i8 1, ptr [[M]], align 1
16 ; CHECK-NEXT:    ret ptr [[M]]
18   %m = call ptr @malloc(i64 24)
19   store i8 0, ptr %m
20   store i8 1, ptr %m
21   ret ptr %m
24 ; Same as @test_return_captures_1, but across BBs.
25 define ptr @test_return_captures_2() {
26 ; CHECK-LABEL: @test_return_captures_2(
27 ; CHECK-NEXT:    [[M:%.*]] = call ptr @malloc(i64 24)
28 ; CHECK-NEXT:    br label [[EXIT:%.*]]
29 ; CHECK:       exit:
30 ; CHECK-NEXT:    store i8 1, ptr [[M]], align 1
31 ; CHECK-NEXT:    ret ptr [[M]]
33   %m = call ptr @malloc(i64 24)
34   store i8 0, ptr %m
35   br label %exit
37 exit:
38   store i8 1, ptr %m
39   ret ptr %m
43 %S1 = type { ptr }
45 ; We cannot remove the last store to %m, because it escapes by storing it to %E.
46 define void @test_malloc_capture_1(ptr %E) {
47 ; CHECK-LABEL: @test_malloc_capture_1(
48 ; CHECK-NEXT:    [[M:%.*]] = call ptr @malloc(i64 24)
49 ; CHECK-NEXT:    br label [[EXIT:%.*]]
50 ; CHECK:       exit:
51 ; CHECK-NEXT:    store ptr [[M]], ptr [[E:%.*]], align 4
52 ; CHECK-NEXT:    store i8 1, ptr [[M]], align 1
53 ; CHECK-NEXT:    ret void
55   %m = call ptr @malloc(i64 24)
56   br label %exit
58 exit:
59   store ptr %m, ptr %E
60   store i8 1, ptr %m
61   ret void
64 ; Check we do not eliminate either store. The first one cannot be eliminated,
65 ; due to the call of @capture. The second one because %m escapes.
66 define ptr @test_malloc_capture_2() {
67 ; CHECK-LABEL: @test_malloc_capture_2(
68 ; CHECK-NEXT:    [[M:%.*]] = call ptr @malloc(i64 24)
69 ; CHECK-NEXT:    store i8 0, ptr [[M]], align 1
70 ; CHECK-NEXT:    call void @capture(ptr [[M]])
71 ; CHECK-NEXT:    br label [[EXIT:%.*]]
72 ; CHECK:       exit:
73 ; CHECK-NEXT:    store i8 1, ptr [[M]], align 1
74 ; CHECK-NEXT:    ret ptr [[M]]
76   %m = call ptr @malloc(i64 24)
77   store i8 0, ptr %m
78   call void @capture(ptr %m)
79   br label %exit
81 exit:
82   store i8 1, ptr %m
83   ret ptr %m
86 ; We can remove the first store store i8 0, ptr %m because there are no throwing
87 ; instructions between the 2 stores and also %m escapes after the killing store.
88 define ptr @test_malloc_capture_3() {
89 ; CHECK-LABEL: @test_malloc_capture_3(
90 ; CHECK-NEXT:    [[M:%.*]] = call ptr @malloc(i64 24)
91 ; CHECK-NEXT:    br label [[EXIT:%.*]]
92 ; CHECK:       exit:
93 ; CHECK-NEXT:    store i8 1, ptr [[M]], align 1
94 ; CHECK-NEXT:    call void @capture(ptr [[M]])
95 ; CHECK-NEXT:    ret ptr [[M]]
97   %m = call ptr @malloc(i64 24)
98   store i8 0, ptr %m
99   br label %exit
101 exit:
102   store i8 1, ptr %m
103   call void @capture(ptr %m)
104   ret ptr %m
107 ; TODO: We could remove the first store store i8 0, ptr %m because %m escapes
108 ; after the killing store.
109 define ptr @test_malloc_capture_4() {
110 ; CHECK-LABEL: @test_malloc_capture_4(
111 ; CHECK-NEXT:    [[M:%.*]] = call ptr @malloc(i64 24)
112 ; CHECK-NEXT:    store i8 0, ptr [[M]], align 1
113 ; CHECK-NEXT:    call void @may_throw_readnone()
114 ; CHECK-NEXT:    br label [[EXIT:%.*]]
115 ; CHECK:       exit:
116 ; CHECK-NEXT:    store i8 1, ptr [[M]], align 1
117 ; CHECK-NEXT:    call void @capture(ptr [[M]])
118 ; CHECK-NEXT:    ret ptr [[M]]
121   %m = call ptr @malloc(i64 24)
122   store i8 0, ptr %m
123   call void @may_throw_readnone()
124   br label %exit
126 exit:
127   store i8 1, ptr %m
128   call void @capture(ptr %m)
129   ret ptr %m
133 ; We cannot remove the first store store i8 0, ptr %m because %m escapes
134 ; before the killing store and we may throw in between.
135 define ptr @test_malloc_capture_5() {
136 ; CHECK-LABEL: @test_malloc_capture_5(
137 ; CHECK-NEXT:    [[M:%.*]] = call ptr @malloc(i64 24)
138 ; CHECK-NEXT:    call void @capture(ptr [[M]])
139 ; CHECK-NEXT:    store i8 0, ptr [[M]], align 1
140 ; CHECK-NEXT:    call void @may_throw_readnone()
141 ; CHECK-NEXT:    br label [[EXIT:%.*]]
142 ; CHECK:       exit:
143 ; CHECK-NEXT:    store i8 1, ptr [[M]], align 1
144 ; CHECK-NEXT:    ret ptr [[M]]
147   %m = call ptr @malloc(i64 24)
148   call void @capture(ptr %m)
149   store i8 0, ptr %m
150   call void @may_throw_readnone()
151   br label %exit
153 exit:
154   store i8 1, ptr %m
155   ret ptr %m
159 ; TODO: We could remove the first store 'store i8 0, ptr %m' even though there
160 ; is a throwing instruction between them, because %m escapes after the killing
161 ; store.
162 define ptr @test_malloc_capture_6() {
163 ; CHECK-LABEL: @test_malloc_capture_6(
164 ; CHECK-NEXT:    [[M:%.*]] = call ptr @malloc(i64 24)
165 ; CHECK-NEXT:    store i8 0, ptr [[M]], align 1
166 ; CHECK-NEXT:    call void @may_throw_readnone()
167 ; CHECK-NEXT:    br label [[EXIT:%.*]]
168 ; CHECK:       exit:
169 ; CHECK-NEXT:    store i8 1, ptr [[M]], align 1
170 ; CHECK-NEXT:    call void @capture(ptr [[M]])
171 ; CHECK-NEXT:    ret ptr [[M]]
174   %m = call ptr @malloc(i64 24)
175   store i8 0, ptr %m
176   call void @may_throw_readnone()
177   br label %exit
179 exit:
180   store i8 1, ptr %m
181   call void @capture(ptr %m)
182   ret ptr %m
185 ; We *could* remove the first store 'store i8 0, ptr %m' even though there is a
186 ; throwing instruction between them, because %m escapes after the killing store.
187 ; But this would require using PointerMayBeCapturedBefore in
188 ; isInvisibleToCallerBeforeRet, which we currently do not do to limit
189 ; compile-time, as this appears to hardly ever lead to more stores eliminated
190 ; in practice.
191 define ptr @test_malloc_capture_7() {
192 ; CHECK-LABEL: @test_malloc_capture_7(
193 ; CHECK-NEXT:    [[M:%.*]] = call ptr @malloc(i64 24)
194 ; CHECK-NEXT:    store i8 0, ptr [[M]], align 1
195 ; CHECK-NEXT:    call void @may_throw()
196 ; CHECK-NEXT:    br label [[EXIT:%.*]]
197 ; CHECK:       exit:
198 ; CHECK-NEXT:    store i8 1, ptr [[M]], align 1
199 ; CHECK-NEXT:    call void @capture(ptr [[M]])
200 ; CHECK-NEXT:    ret ptr [[M]]
203   %m = call ptr @malloc(i64 24)
204   store i8 0, ptr %m
205   call void @may_throw()
206   br label %exit
208 exit:
209   store i8 1, ptr %m
210   call void @capture(ptr %m)
211   ret ptr %m
214 ; Stores to stack objects can be eliminated if they are not captured inside the function.
215 define void @test_alloca_nocapture_1() {
216 ; CHECK-LABEL: @test_alloca_nocapture_1(
217 ; CHECK-NEXT:    call void @foo()
218 ; CHECK-NEXT:    br label [[EXIT:%.*]]
219 ; CHECK:       exit:
220 ; CHECK-NEXT:    ret void
222   %m = alloca i8
223   store i8 0, ptr %m
224   call void @foo()
225   br label %exit
227 exit:
228   store i8 1, ptr %m
229   ret void
232 ; Cannot remove first store i8 0, ptr %m, as the call to @capture captures the object.
233 define void @test_alloca_capture_1() {
234 ; CHECK-LABEL: @test_alloca_capture_1(
235 ; CHECK-NEXT:    [[M:%.*]] = alloca i8, align 1
236 ; CHECK-NEXT:    store i8 0, ptr [[M]], align 1
237 ; CHECK-NEXT:    call void @capture(ptr [[M]])
238 ; CHECK-NEXT:    br label [[EXIT:%.*]]
239 ; CHECK:       exit:
240 ; CHECK-NEXT:    ret void
242   %m = alloca i8
243   store i8 0, ptr %m
244   call void @capture(ptr %m)
245   br label %exit
247 exit:
248   store i8 1, ptr %m
249   ret void
252 ; We can remove the last store to %m, even though it escapes because the alloca
253 ; becomes invalid after the function returns.
254 define void @test_alloca_capture_2(ptr %E) {
255 ; CHECK-LABEL: @test_alloca_capture_2(
256 ; CHECK-NEXT:    [[M:%.*]] = alloca i8, align 1
257 ; CHECK-NEXT:    br label [[EXIT:%.*]]
258 ; CHECK:       exit:
259 ; CHECK-NEXT:    store ptr [[M]], ptr [[E:%.*]], align 4
260 ; CHECK-NEXT:    ret void
262   %m = alloca i8
263   br label %exit
265 exit:
266   store ptr %m, ptr %E
267   store i8 1, ptr %m
268   ret void
271 ; Readnone functions are not modeled in MemorySSA, but could throw.
272 ; Make sure we do not eliminate the first store 'store i8 2, ptr %call'
273 define void @malloc_capture_throw_1() {
274 ; CHECK-LABEL: @malloc_capture_throw_1(
275 ; CHECK-NEXT:    [[CALL:%.*]] = call ptr @malloc(i64 1)
276 ; CHECK-NEXT:    call void @may_capture(ptr [[CALL]])
277 ; CHECK-NEXT:    store i8 2, ptr [[CALL]], align 1
278 ; CHECK-NEXT:    call void @may_throw_readnone()
279 ; CHECK-NEXT:    store i8 3, ptr [[CALL]], align 1
280 ; CHECK-NEXT:    ret void
282   %call = call ptr @malloc(i64 1)
283   call void @may_capture(ptr %call)
284   store i8 2, ptr %call, align 1
285   call void @may_throw_readnone()
286   store i8 3, ptr %call, align 1
287   ret void
290 ; Readnone functions are not modeled in MemorySSA, but could throw.
291 ; Make sure we do not eliminate the first store 'store i8 2, ptr %call'
292 define void @malloc_capture_throw_2() {
293 ; CHECK-LABEL: @malloc_capture_throw_2(
294 ; CHECK-NEXT:    [[CALL:%.*]] = call ptr @malloc(i64 1)
295 ; CHECK-NEXT:    call void @may_capture(ptr [[CALL]])
296 ; CHECK-NEXT:    store i8 2, ptr [[CALL]], align 1
297 ; CHECK-NEXT:    br label [[BB:%.*]]
298 ; CHECK:       bb:
299 ; CHECK-NEXT:    call void @may_throw_readnone()
300 ; CHECK-NEXT:    store i8 3, ptr [[CALL]], align 1
301 ; CHECK-NEXT:    ret void
303   %call = call ptr @malloc(i64 1)
304   call void @may_capture(ptr %call)
305   store i8 2, ptr %call, align 1
306   br label %bb
309   call void @may_throw_readnone()
310   store i8 3, ptr %call, align 1
311   ret void
315 declare void @may_capture(ptr)
316 declare void @may_throw_readnone() readnone
317 declare void @may_throw()