[sanitizer] Improve FreeBSD ASLR detection
[llvm-project.git] / llvm / test / Transforms / DeadStoreElimination / multiblock-captures.ll
blob45f3e2c429754e1ce72b68798c1ef3f31ee2922b
1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt < %s -basic-aa -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 i8* @malloc(i64)
8 declare void @foo()
9 declare void @capture(i8*)
11 ; Check that we do not remove the second store, as %m is returned.
12 define i8* @test_return_captures_1() {
13 ; CHECK-LABEL: @test_return_captures_1(
14 ; CHECK-NEXT:    [[M:%.*]] = call i8* @malloc(i64 24)
15 ; CHECK-NEXT:    store i8 1, i8* [[M]], align 1
16 ; CHECK-NEXT:    ret i8* [[M]]
18   %m = call i8* @malloc(i64 24)
19   store i8 0, i8* %m
20   store i8 1, i8* %m
21   ret i8* %m
24 ; Same as @test_return_captures_1, but across BBs.
25 define i8* @test_return_captures_2() {
26 ; CHECK-LABEL: @test_return_captures_2(
27 ; CHECK-NEXT:    [[M:%.*]] = call i8* @malloc(i64 24)
28 ; CHECK-NEXT:    br label [[EXIT:%.*]]
29 ; CHECK:       exit:
30 ; CHECK-NEXT:    store i8 1, i8* [[M]], align 1
31 ; CHECK-NEXT:    ret i8* [[M]]
33   %m = call i8* @malloc(i64 24)
34   store i8 0, i8* %m
35   br label %exit
37 exit:
38   store i8 1, i8* %m
39   ret i8* %m
43 %S1 = type { i8 * }
45 ; We cannot remove the last store to %m, because it escapes by storing it to %E.
46 define void @test_malloc_capture_1(%S1* %E) {
47 ; CHECK-LABEL: @test_malloc_capture_1(
48 ; CHECK-NEXT:    [[M:%.*]] = call i8* @malloc(i64 24)
49 ; CHECK-NEXT:    br label [[EXIT:%.*]]
50 ; CHECK:       exit:
51 ; CHECK-NEXT:    [[F_PTR:%.*]] = getelementptr [[S1:%.*]], %S1* [[E:%.*]], i32 0, i32 0
52 ; CHECK-NEXT:    store i8* [[M]], i8** [[F_PTR]], align 4
53 ; CHECK-NEXT:    store i8 1, i8* [[M]], align 1
54 ; CHECK-NEXT:    ret void
56   %m = call i8* @malloc(i64 24)
57   br label %exit
59 exit:
60   %f.ptr = getelementptr %S1, %S1* %E, i32 0, i32 0
61   store i8* %m, i8** %f.ptr
62   store i8 1, i8* %m
63   ret void
66 ; Check we do not eliminate either store. The first one cannot be eliminated,
67 ; due to the call of @capture. The second one because %m escapes.
68 define i8* @test_malloc_capture_2() {
69 ; CHECK-LABEL: @test_malloc_capture_2(
70 ; CHECK-NEXT:    [[M:%.*]] = call i8* @malloc(i64 24)
71 ; CHECK-NEXT:    store i8 0, i8* [[M]], align 1
72 ; CHECK-NEXT:    call void @capture(i8* [[M]])
73 ; CHECK-NEXT:    br label [[EXIT:%.*]]
74 ; CHECK:       exit:
75 ; CHECK-NEXT:    store i8 1, i8* [[M]], align 1
76 ; CHECK-NEXT:    ret i8* [[M]]
78   %m = call i8* @malloc(i64 24)
79   store i8 0, i8* %m
80   call void @capture(i8* %m)
81   br label %exit
83 exit:
84   store i8 1, i8* %m
85   ret i8* %m
88 ; We can remove the first store store i8 0, i8* %m because there are no throwing
89 ; instructions between the 2 stores and also %m escapes after the killing store.
90 define i8* @test_malloc_capture_3() {
91 ; CHECK-LABEL: @test_malloc_capture_3(
92 ; CHECK-NEXT:    [[M:%.*]] = call i8* @malloc(i64 24)
93 ; CHECK-NEXT:    br label [[EXIT:%.*]]
94 ; CHECK:       exit:
95 ; CHECK-NEXT:    store i8 1, i8* [[M]], align 1
96 ; CHECK-NEXT:    call void @capture(i8* [[M]])
97 ; CHECK-NEXT:    ret i8* [[M]]
99   %m = call i8* @malloc(i64 24)
100   store i8 0, i8* %m
101   br label %exit
103 exit:
104   store i8 1, i8* %m
105   call void @capture(i8* %m)
106   ret i8* %m
109 ; TODO: We could remove the first store store i8 0, i8* %m because %m escapes
110 ; after the killing store.
111 define i8* @test_malloc_capture_4() {
112 ; CHECK-LABEL: @test_malloc_capture_4(
113 ; CHECK-NEXT:    [[M:%.*]] = call i8* @malloc(i64 24)
114 ; CHECK-NEXT:    store i8 0, i8* [[M]], align 1
115 ; CHECK-NEXT:    call void @may_throw_readnone()
116 ; CHECK-NEXT:    br label [[EXIT:%.*]]
117 ; CHECK:       exit:
118 ; CHECK-NEXT:    store i8 1, i8* [[M]], align 1
119 ; CHECK-NEXT:    call void @capture(i8* [[M]])
120 ; CHECK-NEXT:    ret i8* [[M]]
123   %m = call i8* @malloc(i64 24)
124   store i8 0, i8* %m
125   call void @may_throw_readnone()
126   br label %exit
128 exit:
129   store i8 1, i8* %m
130   call void @capture(i8* %m)
131   ret i8* %m
135 ; We cannot remove the first store store i8 0, i8* %m because %m escapes
136 ; before the killing store and we may throw in between.
137 define i8* @test_malloc_capture_5() {
138 ; CHECK-LABEL: @test_malloc_capture_5(
139 ; CHECK-NEXT:    [[M:%.*]] = call i8* @malloc(i64 24)
140 ; CHECK-NEXT:    call void @capture(i8* [[M]])
141 ; CHECK-NEXT:    store i8 0, i8* [[M]], align 1
142 ; CHECK-NEXT:    call void @may_throw_readnone()
143 ; CHECK-NEXT:    br label [[EXIT:%.*]]
144 ; CHECK:       exit:
145 ; CHECK-NEXT:    store i8 1, i8* [[M]], align 1
146 ; CHECK-NEXT:    ret i8* [[M]]
149   %m = call i8* @malloc(i64 24)
150   call void @capture(i8* %m)
151   store i8 0, i8* %m
152   call void @may_throw_readnone()
153   br label %exit
155 exit:
156   store i8 1, i8* %m
157   ret i8* %m
161 ; TODO: We could remove the first store 'store i8 0, i8* %m' even though there
162 ; is a throwing instruction between them, because %m escapes after the killing
163 ; store.
164 define i8* @test_malloc_capture_6() {
165 ; CHECK-LABEL: @test_malloc_capture_6(
166 ; CHECK-NEXT:    [[M:%.*]] = call i8* @malloc(i64 24)
167 ; CHECK-NEXT:    store i8 0, i8* [[M]], align 1
168 ; CHECK-NEXT:    call void @may_throw_readnone()
169 ; CHECK-NEXT:    br label [[EXIT:%.*]]
170 ; CHECK:       exit:
171 ; CHECK-NEXT:    store i8 1, i8* [[M]], align 1
172 ; CHECK-NEXT:    call void @capture(i8* [[M]])
173 ; CHECK-NEXT:    ret i8* [[M]]
176   %m = call i8* @malloc(i64 24)
177   store i8 0, i8* %m
178   call void @may_throw_readnone()
179   br label %exit
181 exit:
182   store i8 1, i8* %m
183   call void @capture(i8* %m)
184   ret i8* %m
187 ; We *could* remove the first store 'store i8 0, i8* %m' even though there is a
188 ; throwing instruction between them, because %m escapes after the killing store.
189 ; But this would require using PointerMayBeCapturedBefore in
190 ; isInvisibleToCallerBeforeRet, which we currently do not do to limit
191 ; compile-time, as this appears to hardly ever lead to more stores eliminated
192 ; in practice.
193 define i8* @test_malloc_capture_7() {
194 ; CHECK-LABEL: @test_malloc_capture_7(
195 ; CHECK-NEXT:    [[M:%.*]] = call i8* @malloc(i64 24)
196 ; CHECK-NEXT:    store i8 0, i8* [[M]], align 1
197 ; CHECK-NEXT:    call void @may_throw()
198 ; CHECK-NEXT:    br label [[EXIT:%.*]]
199 ; CHECK:       exit:
200 ; CHECK-NEXT:    store i8 1, i8* [[M]], align 1
201 ; CHECK-NEXT:    call void @capture(i8* [[M]])
202 ; CHECK-NEXT:    ret i8* [[M]]
205   %m = call i8* @malloc(i64 24)
206   store i8 0, i8* %m
207   call void @may_throw()
208   br label %exit
210 exit:
211   store i8 1, i8* %m
212   call void @capture(i8* %m)
213   ret i8* %m
216 ; Stores to stack objects can be eliminated if they are not captured inside the function.
217 define void @test_alloca_nocapture_1() {
218 ; CHECK-LABEL: @test_alloca_nocapture_1(
219 ; CHECK-NEXT:    call void @foo()
220 ; CHECK-NEXT:    br label [[EXIT:%.*]]
221 ; CHECK:       exit:
222 ; CHECK-NEXT:    ret void
224   %m = alloca i8
225   store i8 0, i8* %m
226   call void @foo()
227   br label %exit
229 exit:
230   store i8 1, i8* %m
231   ret void
234 ; Cannot remove first store i8 0, i8* %m, as the call to @capture captures the object.
235 define void @test_alloca_capture_1() {
236 ; CHECK-LABEL: @test_alloca_capture_1(
237 ; CHECK-NEXT:    [[M:%.*]] = alloca i8, align 1
238 ; CHECK-NEXT:    store i8 0, i8* [[M]], align 1
239 ; CHECK-NEXT:    call void @capture(i8* [[M]])
240 ; CHECK-NEXT:    br label [[EXIT:%.*]]
241 ; CHECK:       exit:
242 ; CHECK-NEXT:    ret void
244   %m = alloca i8
245   store i8 0, i8* %m
246   call void @capture(i8* %m)
247   br label %exit
249 exit:
250   store i8 1, i8* %m
251   ret void
254 ; We can remove the last store to %m, even though it escapes because the alloca
255 ; becomes invalid after the function returns.
256 define void @test_alloca_capture_2(%S1* %E) {
257 ; CHECK-LABEL: @test_alloca_capture_2(
258 ; CHECK-NEXT:    [[M:%.*]] = alloca i8, align 1
259 ; CHECK-NEXT:    br label [[EXIT:%.*]]
260 ; CHECK:       exit:
261 ; CHECK-NEXT:    [[F_PTR:%.*]] = getelementptr [[S1:%.*]], %S1* [[E:%.*]], i32 0, i32 0
262 ; CHECK-NEXT:    store i8* [[M]], i8** [[F_PTR]], align 4
263 ; CHECK-NEXT:    ret void
265   %m = alloca i8
266   br label %exit
268 exit:
269   %f.ptr = getelementptr %S1, %S1* %E, i32 0, i32 0
270   store i8* %m, i8** %f.ptr
271   store i8 1, i8* %m
272   ret void
275 ; Readnone functions are not modeled in MemorySSA, but could throw.
276 ; Make sure we do not eliminate the first store 'store i8 2, i8* %call'
277 define void @malloc_capture_throw_1() {
278 ; CHECK-LABEL: @malloc_capture_throw_1(
279 ; CHECK-NEXT:    [[CALL:%.*]] = call i8* @malloc(i64 1)
280 ; CHECK-NEXT:    call void @may_capture(i8* [[CALL]])
281 ; CHECK-NEXT:    store i8 2, i8* [[CALL]], align 1
282 ; CHECK-NEXT:    call void @may_throw_readnone()
283 ; CHECK-NEXT:    store i8 3, i8* [[CALL]], align 1
284 ; CHECK-NEXT:    ret void
286   %call = call i8* @malloc(i64 1)
287   call void @may_capture(i8* %call)
288   store i8 2, i8* %call, align 1
289   call void @may_throw_readnone()
290   store i8 3, i8* %call, align 1
291   ret void
294 ; Readnone functions are not modeled in MemorySSA, but could throw.
295 ; Make sure we do not eliminate the first store 'store i8 2, i8* %call'
296 define void @malloc_capture_throw_2() {
297 ; CHECK-LABEL: @malloc_capture_throw_2(
298 ; CHECK-NEXT:    [[CALL:%.*]] = call i8* @malloc(i64 1)
299 ; CHECK-NEXT:    call void @may_capture(i8* [[CALL]])
300 ; CHECK-NEXT:    store i8 2, i8* [[CALL]], align 1
301 ; CHECK-NEXT:    br label [[BB:%.*]]
302 ; CHECK:       bb:
303 ; CHECK-NEXT:    call void @may_throw_readnone()
304 ; CHECK-NEXT:    store i8 3, i8* [[CALL]], align 1
305 ; CHECK-NEXT:    ret void
307   %call = call i8* @malloc(i64 1)
308   call void @may_capture(i8* %call)
309   store i8 2, i8* %call, align 1
310   br label %bb
313   call void @may_throw_readnone()
314   store i8 3, i8* %call, align 1
315   ret void
319 declare void @may_capture(i8*)
320 declare void @may_throw_readnone() readnone
321 declare void @may_throw()