[ARM] Better OR's for MVE compares
[llvm-core.git] / test / Analysis / StackSafetyAnalysis / ipa.ll
blob6791dd0866b85bb1bf7d49b48d539e091406575f
1 ; RUN: llvm-as %s -o %t0.bc
2 ; RUN: llvm-as %S/Inputs/ipa.ll -o %t1.bc
3 ; RUN: llvm-link -disable-lazy-loading %t0.bc %t1.bc -o %t.combined.bc
4 ; RUN: opt -S -analyze -stack-safety-local %t.combined.bc | FileCheck %s --check-prefixes=CHECK,LOCAL
5 ; RUN: opt -S -passes="print<stack-safety-local>" -disable-output %t.combined.bc 2>&1 | FileCheck %s --check-prefixes=CHECK,LOCAL
6 ; RUN: opt -S -analyze -stack-safety %t.combined.bc | FileCheck %s --check-prefixes=CHECK,GLOBAL
7 ; RUN: opt -S -passes="print-stack-safety" -disable-output %t.combined.bc 2>&1 | FileCheck %s --check-prefixes=CHECK,GLOBAL
9 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
10 target triple = "x86_64-unknown-linux-gnu"
12 declare void @Write1(i8* %p)
13 declare void @Write4(i8* %p)
14 declare void @Write4_2(i8* %p, i8* %q)
15 declare void @Write8(i8* %p)
16 declare dso_local i8* @WriteAndReturn8(i8* %p)
17 declare dso_local void @ExternalCall(i8* %p)
18 declare void @PreemptableWrite1(i8* %p)
19 declare void @InterposableWrite1(i8* %p)
20 declare i8* @ReturnDependent(i8* %p)
21 declare void @Rec2(i8* %p)
22 declare void @RecursiveNoOffset(i32* %p, i32 %size, i32* %acc)
23 declare void @RecursiveWithOffset(i32 %size, i32* %acc)
25 ; Basic out-of-bounds.
26 define void @f1() {
27 ; CHECK-LABEL: @f1 dso_preemptable{{$}}
28 ; CHECK-NEXT: args uses:
29 ; CHECK-NEXT: allocas uses:
30 ; LOCAL-NEXT: x[4]: empty-set, @Write8(arg0, [0,1)){{$}}
31 ; GLOBAL-NEXT: x[4]: [0,8), @Write8(arg0, [0,1)){{$}}
32 ; CHECK-NOT: ]:
33 entry:
34   %x = alloca i32, align 4
35   %x1 = bitcast i32* %x to i8*
36   call void @Write8(i8* %x1)
37   ret void
40 ; Basic in-bounds.
41 define void @f2() {
42 ; CHECK-LABEL: @f2 dso_preemptable{{$}}
43 ; CHECK-NEXT: args uses:
44 ; CHECK-NEXT: allocas uses:
45 ; LOCAL-NEXT: x[4]: empty-set, @Write1(arg0, [0,1)){{$}}
46 ; GLOBAL-NEXT: x[4]: [0,1), @Write1(arg0, [0,1)){{$}}
47 ; CHECK-NOT: ]:
48 entry:
49   %x = alloca i32, align 4
50   %x1 = bitcast i32* %x to i8*
51   call void @Write1(i8* %x1)
52   ret void
55 ; Another basic in-bounds.
56 define void @f3() {
57 ; CHECK-LABEL: @f3 dso_preemptable{{$}}
58 ; CHECK-NEXT: args uses:
59 ; CHECK-NEXT: allocas uses:
60 ; LOCAL-NEXT: x[4]: empty-set, @Write4(arg0, [0,1)){{$}}
61 ; GLOBAL-NEXT: x[4]: [0,4), @Write4(arg0, [0,1)){{$}}
62 ; CHECK-NOT: ]:
63 entry:
64   %x = alloca i32, align 4
65   %x1 = bitcast i32* %x to i8*
66   call void @Write4(i8* %x1)
67   ret void
70 ; In-bounds with offset.
71 define void @f4() {
72 ; CHECK-LABEL: @f4 dso_preemptable{{$}}
73 ; CHECK-NEXT: args uses:
74 ; CHECK-NEXT: allocas uses:
75 ; LOCAL-NEXT: x[4]: empty-set, @Write1(arg0, [1,2)){{$}}
76 ; GLOBAL-NEXT: x[4]: [1,2), @Write1(arg0, [1,2)){{$}}
77 ; CHECK-NOT: ]:
78 entry:
79   %x = alloca i32, align 4
80   %x1 = bitcast i32* %x to i8*
81   %x2 = getelementptr i8, i8* %x1, i64 1
82   call void @Write1(i8* %x2)
83   ret void
86 ; Out-of-bounds with offset.
87 define void @f5() {
88 ; CHECK-LABEL: @f5 dso_preemptable{{$}}
89 ; CHECK-NEXT: args uses:
90 ; CHECK-NEXT: allocas uses:
91 ; LOCAL-NEXT: empty-set, @Write4(arg0, [1,2)){{$}}
92 ; GLOBAL-NEXT: [1,5), @Write4(arg0, [1,2)){{$}}
93 ; CHECK-NOT: ]:
94 entry:
95   %x = alloca i32, align 4
96   %x1 = bitcast i32* %x to i8*
97   %x2 = getelementptr i8, i8* %x1, i64 1
98   call void @Write4(i8* %x2)
99   ret void
102 ; External call.
103 define void @f6() {
104 ; CHECK-LABEL: @f6 dso_preemptable{{$}}
105 ; CHECK-NEXT: args uses:
106 ; CHECK-NEXT: allocas uses:
107 ; LOCAL-NEXT: x[4]: empty-set, @ExternalCall(arg0, [0,1)){{$}}
108 ; GLOBAL-NEXT: x[4]: full-set, @ExternalCall(arg0, [0,1)){{$}}
109 ; CHECK-NOT: ]:
110 entry:
111   %x = alloca i32, align 4
112   %x1 = bitcast i32* %x to i8*
113   call void @ExternalCall(i8* %x1)
114   ret void
117 ; Call to dso_preemptable function
118 define void @PreemptableCall() {
119 ; CHECK-LABEL: @PreemptableCall dso_preemptable{{$}}
120 ; CHECK-NEXT: args uses:
121 ; CHECK-NEXT: allocas uses:
122 ; LOCAL-NEXT: x[4]: empty-set, @PreemptableWrite1(arg0, [0,1)){{$}}
123 ; GLOBAL-NEXT: x[4]: full-set, @PreemptableWrite1(arg0, [0,1)){{$}}
124 ; CHECK-NOT: ]:
125 entry:
126   %x = alloca i32, align 4
127   %x1 = bitcast i32* %x to i8*
128   call void @PreemptableWrite1(i8* %x1)
129   ret void
132 ; Call to function with interposable linkage
133 define void @InterposableCall() {
134 ; CHECK-LABEL: @InterposableCall dso_preemptable{{$}}
135 ; CHECK-NEXT: args uses:
136 ; CHECK-NEXT: allocas uses:
137 ; LOCAL-NEXT: x[4]: empty-set, @InterposableWrite1(arg0, [0,1)){{$}}
138 ; GLOBAL-NEXT: x[4]: full-set, @InterposableWrite1(arg0, [0,1)){{$}}
139 ; CHECK-NOT: ]:
140 entry:
141   %x = alloca i32, align 4
142   %x1 = bitcast i32* %x to i8*
143   call void @InterposableWrite1(i8* %x1)
144   ret void
147 ; Call to function with private linkage
148 define void @PrivateCall() {
149 ; CHECK-LABEL: @PrivateCall dso_preemptable{{$}}
150 ; CHECK-NEXT: args uses:
151 ; CHECK-NEXT: allocas uses:
152 ; LOCAL-NEXT: x[4]: empty-set, @PrivateWrite1(arg0, [0,1)){{$}}
153 ; GLOBAL-NEXT: x[4]: [0,1), @PrivateWrite1(arg0, [0,1)){{$}}
154 ; CHECK-NOT: ]:
155 entry:
156   %x = alloca i32, align 4
157   %x1 = bitcast i32* %x to i8*
158   call void @PrivateWrite1(i8* %x1)
159   ret void
162 define private void @PrivateWrite1(i8* %p) {
163 ; CHECK-LABEL: @PrivateWrite1{{$}}
164 ; CHECK-NEXT: args uses:
165 ; CHECK-NEXT: p[]: [0,1){{$}}
166 ; CHECK-NEXT: allocas uses:
167 ; CHECK-NOT: ]:
168 entry:
169   store i8 0, i8* %p, align 1
170   ret void
173 ; Caller returns a dependent value.
174 ; FIXME: alloca considered unsafe even if the return value is unused.
175 define void @f7() {
176 ; CHECK-LABEL: @f7 dso_preemptable{{$}}
177 ; CHECK-NEXT: args uses:
178 ; CHECK-NEXT: allocas uses:
179 ; LOCAL-NEXT: x[4]: empty-set, @ReturnDependent(arg0, [0,1)){{$}}
180 ; GLOBAL-NEXT: x[4]: full-set, @ReturnDependent(arg0, [0,1)){{$}}
181 ; CHECK-NOT: ]:
182 entry:
183   %x = alloca i32, align 4
184   %x1 = bitcast i32* %x to i8*
185   %x2 = call i8* @ReturnDependent(i8* %x1)
186   ret void
189 define void @f8left() {
190 ; CHECK-LABEL: @f8left dso_preemptable{{$}}
191 ; CHECK-NEXT: args uses:
192 ; CHECK-NEXT: allocas uses:
193 ; LOCAL-NEXT: x[8]: empty-set, @Rec2(arg0, [2,3)){{$}}
194 ; GLOBAL-NEXT: x[8]: [0,4), @Rec2(arg0, [2,3)){{$}}
195 ; CHECK-NOT: ]:
196 entry:
197   %x = alloca i64, align 4
198   %x1 = bitcast i64* %x to i8*
199   %x2 = getelementptr i8, i8* %x1, i64 2
200 ; 2 + [-2, 2) = [0, 4) => OK
201   call void @Rec2(i8* %x2)
202   ret void
205 define void @f8right() {
206 ; CHECK-LABEL: @f8right dso_preemptable{{$}}
207 ; CHECK-NEXT: args uses:
208 ; CHECK-NEXT: allocas uses:
209 ; LOCAL-NEXT: x[8]: empty-set, @Rec2(arg0, [6,7)){{$}}
210 ; GLOBAL-NEXT: x[8]: [4,8), @Rec2(arg0, [6,7)){{$}}
211 ; CHECK-NOT: ]:
212 entry:
213   %x = alloca i64, align 4
214   %x1 = bitcast i64* %x to i8*
215   %x2 = getelementptr i8, i8* %x1, i64 6
216 ; 6 + [-2, 2) = [4, 8) => OK
217   call void @Rec2(i8* %x2)
218   ret void
221 define void @f8oobleft() {
222 ; CHECK-LABEL: @f8oobleft dso_preemptable{{$}}
223 ; CHECK-NEXT: args uses:
224 ; CHECK-NEXT: allocas uses:
225 ; LOCAL-NEXT: x[8]: empty-set, @Rec2(arg0, [1,2)){{$}}
226 ; GLOBAL-NEXT: x[8]: [-1,3), @Rec2(arg0, [1,2)){{$}}
227 ; CHECK-NOT: ]:
228 entry:
229   %x = alloca i64, align 4
230   %x1 = bitcast i64* %x to i8*
231   %x2 = getelementptr i8, i8* %x1, i64 1
232 ; 1 + [-2, 2) = [-1, 3) => NOT OK
233   call void @Rec2(i8* %x2)
234   ret void
237 define void @f8oobright() {
238 ; CHECK-LABEL: @f8oobright dso_preemptable{{$}}
239 ; CHECK-NEXT: args uses:
240 ; CHECK-NEXT: allocas uses:
241 ; LOCAL-NEXT: x[8]: empty-set, @Rec2(arg0, [7,8)){{$}}
242 ; GLOBAL-NEXT: x[8]: [5,9), @Rec2(arg0, [7,8)){{$}}
243 ; CHECK-NOT: ]:
244 entry:
245   %x = alloca i64, align 4
246   %x1 = bitcast i64* %x to i8*
247   %x2 = getelementptr i8, i8* %x1, i64 7
248 ; 7 + [-2, 2) = [5, 9) => NOT OK
249   call void @Rec2(i8* %x2)
250   ret void
253 define void @TwoArguments() {
254 ; CHECK-LABEL: @TwoArguments dso_preemptable{{$}}
255 ; CHECK-NEXT: args uses:
256 ; CHECK-NEXT: allocas uses:
257 ; LOCAL-NEXT: x[8]: empty-set, @Write4_2(arg1, [0,1)), @Write4_2(arg0, [4,5)){{$}}
258 ; GLOBAL-NEXT: x[8]: [0,8), @Write4_2(arg1, [0,1)), @Write4_2(arg0, [4,5)){{$}}
259 ; CHECK-NOT: ]:
260 entry:
261   %x = alloca i64, align 4
262   %x1 = bitcast i64* %x to i8*
263   %x2 = getelementptr i8, i8* %x1, i64 4
264   call void @Write4_2(i8* %x2, i8* %x1)
265   ret void
268 define void @TwoArgumentsOOBOne() {
269 ; CHECK-LABEL: @TwoArgumentsOOBOne dso_preemptable{{$}}
270 ; CHECK-NEXT: args uses:
271 ; CHECK-NEXT: allocas uses:
272 ; LOCAL-NEXT: x[8]: empty-set, @Write4_2(arg1, [0,1)), @Write4_2(arg0, [5,6)){{$}}
273 ; GLOBAL-NEXT: x[8]: [0,9), @Write4_2(arg1, [0,1)), @Write4_2(arg0, [5,6)){{$}}
274 ; CHECK-NOT: ]:
275 entry:
276   %x = alloca i64, align 4
277   %x1 = bitcast i64* %x to i8*
278   %x2 = getelementptr i8, i8* %x1, i64 5
279   call void @Write4_2(i8* %x2, i8* %x1)
280   ret void
283 define void @TwoArgumentsOOBOther() {
284 ; CHECK-LABEL: @TwoArgumentsOOBOther dso_preemptable{{$}}
285 ; CHECK-NEXT: args uses:
286 ; CHECK-NEXT: allocas uses:
287 ; LOCAL-NEXT: x[8]: empty-set, @Write4_2(arg1, [-1,0)), @Write4_2(arg0, [4,5)){{$}}
288 ; GLOBAL-NEXT: x[8]: [-1,8), @Write4_2(arg1, [-1,0)), @Write4_2(arg0, [4,5)){{$}}
289 ; CHECK-NOT: ]:
290 entry:
291   %x = alloca i64, align 4
292   %x0 = bitcast i64* %x to i8*
293   %x1 = getelementptr i8, i8* %x0, i64 -1
294   %x2 = getelementptr i8, i8* %x0, i64 4
295   call void @Write4_2(i8* %x2, i8* %x1)
296   ret void
299 define void @TwoArgumentsOOBBoth() {
300 ; CHECK-LABEL: @TwoArgumentsOOBBoth dso_preemptable{{$}}
301 ; CHECK-NEXT: args uses:
302 ; CHECK-NEXT: allocas uses:
303 ; LOCAL-NEXT: x[8]: empty-set, @Write4_2(arg1, [-1,0)), @Write4_2(arg0, [5,6)){{$}}
304 ; GLOBAL-NEXT: x[8]: [-1,9), @Write4_2(arg1, [-1,0)), @Write4_2(arg0, [5,6)){{$}}
305 ; CHECK-NOT: ]:
306 entry:
307   %x = alloca i64, align 4
308   %x0 = bitcast i64* %x to i8*
309   %x1 = getelementptr i8, i8* %x0, i64 -1
310   %x2 = getelementptr i8, i8* %x0, i64 5
311   call void @Write4_2(i8* %x2, i8* %x1)
312   ret void
315 define i32 @TestRecursiveNoOffset(i32* %p, i32 %size) {
316 ; CHECK-LABEL: @TestRecursiveNoOffset dso_preemptable{{$}}
317 ; CHECK-NEXT: args uses:
318 ; LOCAL-NEXT: p[]: empty-set, @RecursiveNoOffset(arg0, [0,1)){{$}}
319 ; GLOBAL-NEXT: p[]: full-set, @RecursiveNoOffset(arg0, [0,1)){{$}}
320 ; CHECK-NEXT: size[]: empty-set, @RecursiveNoOffset(arg1, [0,1)){{$}}
321 ; CHECK-NEXT: allocas uses:
322 ; CHECK-NEXT: sum[4]: [0,4), @RecursiveNoOffset(arg2, [0,1)){{$}}
323 ; CHECK-NOT: ]:
324 entry:
325   %sum = alloca i32, align 4
326   %0 = bitcast i32* %sum to i8*
327   store i32 0, i32* %sum, align 4
328   call void @RecursiveNoOffset(i32* %p, i32 %size, i32* %sum)
329   %1 = load i32, i32* %sum, align 4
330   ret i32 %1
333 define void @TestRecursiveWithOffset(i32 %size) {
334 ; CHECK-LABEL: @TestRecursiveWithOffset dso_preemptable{{$}}
335 ; CHECK-NEXT: args uses:
336 ; CHECK-NEXT: size[]: empty-set, @RecursiveWithOffset(arg0, [0,1)){{$}}
337 ; CHECK-NEXT: allocas uses:
338 ; LOCAL-NEXT: sum[64]: empty-set, @RecursiveWithOffset(arg1, [0,1)){{$}}
339 ; GLOBAL-NEXT: sum[64]: full-set, @RecursiveWithOffset(arg1, [0,1)){{$}}
340 ; CHECK-NOT: ]:
341 entry:
342   %sum = alloca i32, i64 16, align 4
343   call void @RecursiveWithOffset(i32 %size, i32* %sum)
344   ret void
347 ; FIXME: IPA should detect that access is safe
348 define void @TestUpdateArg() {
349 ; CHECK-LABEL: @TestUpdateArg dso_preemptable{{$}}
350 ; CHECK-NEXT: args uses:
351 ; CHECK-NEXT: allocas uses:
352 ; LOCAL-NEXT: x[16]: empty-set, @WriteAndReturn8(arg0, [0,1)){{$}}
353 ; GLOBAL-NEXT: x[16]: full-set, @WriteAndReturn8(arg0, [0,1)){{$}}
354 ; CHECK-NOT: ]:
355 entry:
356   %x = alloca i8, i64 16, align 4
357   %0 = call i8* @WriteAndReturn8(i8* %x)
358   ret void
361 ; The rest is from Inputs/ipa.ll
363 ; CHECK-LABEL: @Write1{{$}}
364 ; CHECK-NEXT: args uses:
365 ; CHECK-NEXT: p[]: [0,1){{$}}
366 ; CHECK-NEXT: allocas uses:
367 ; CHECK-NOT: ]:
369 ; CHECK-LABEL: @Write4{{$}}
370 ; CHECK-NEXT: args uses:
371 ; CHECK-NEXT: p[]: [0,4){{$}}
372 ; CHECK-NEXT: allocas uses:
373 ; CHECK-NOT: ]:
375 ; CHECK-LABEL: @Write4_2{{$}}
376 ; CHECK-NEXT: args uses:
377 ; CHECK-NEXT: p[]: [0,4){{$}}
378 ; CHECK-NEXT: q[]: [0,4){{$}}
379 ; CHECK-NEXT: allocas uses:
380 ; CHECK-NOT: ]:
382 ; CHECK-LABEL: @Write8{{$}}
383 ; CHECK-NEXT: args uses:
384 ; CHECK-NEXT: p[]: [0,8){{$}}
385 ; CHECK-NEXT: allocas uses:
386 ; CHECK-NOT: ]:
388 ; CHECK-LABEL: @WriteAndReturn8{{$}}
389 ; CHECK-NEXT: args uses:
390 ; CHECK-NEXT: p[]: full-set{{$}}
391 ; CHECK-NEXT: allocas uses:
392 ; CHECK-NOT: ]:
394 ; CHECK-LABEL: @PreemptableWrite1 dso_preemptable{{$}}
395 ; CHECK-NEXT: args uses:
396 ; CHECK-NEXT: p[]: [0,1){{$}}
397 ; CHECK-NEXT: allocas uses:
398 ; CHECK-NOT: ]:
400 ; CHECK-LABEL: @InterposableWrite1 interposable{{$}}
401 ; CHECK-NEXT: args uses:
402 ; CHECK-NEXT: p[]: [0,1){{$}}
403 ; CHECK-NEXT: allocas uses:
404 ; CHECK-NOT: ]:
406 ; CHECK-LABEL: @ReturnDependent{{$}}
407 ; CHECK-NEXT: args uses:
408 ; CHECK-NEXT: p[]: full-set{{$}}
409 ; CHECK-NEXT: allocas uses:
410 ; CHECK-NOT: ]:
412 ; CHECK-LABEL: @Rec0{{$}}
413 ; CHECK-NEXT: args uses:
414 ; LOCAL-NEXT: p[]: empty-set, @Write4(arg0, [2,3)){{$}}
415 ; GLOBAL-NEXT: p[]: [2,6), @Write4(arg0, [2,3)){{$}}
416 ; CHECK-NEXT: allocas uses:
417 ; CHECK-NOT: ]:
419 ; CHECK-LABEL: @Rec1{{$}}
420 ; CHECK-NEXT: args uses:
421 ; LOCAL-NEXT: p[]: empty-set, @Rec0(arg0, [1,2)){{$}}
422 ; GLOBAL-NEXT: p[]: [3,7), @Rec0(arg0, [1,2)){{$}}
423 ; CHECK-NEXT: allocas uses:
424 ; CHECK-NOT: ]:
426 ; CHECK-LABEL: @Rec2{{$}}
427 ; CHECK-NEXT: args uses:
428 ; LOCAL-NEXT: p[]: empty-set, @Rec1(arg0, [-5,-4)){{$}}
429 ; GLOBAL-NEXT: p[]: [-2,2), @Rec1(arg0, [-5,-4)){{$}}
430 ; CHECK-NEXT: allocas uses:
431 ; CHECK-NOT: ]:
433 ; CHECK-LABEL: @RecursiveNoOffset{{$}}
434 ; CHECK-NEXT: args uses:
435 ; LOCAL-NEXT: p[]: [0,4), @RecursiveNoOffset(arg0, [4,5)){{$}}
436 ; GLOBAL-NEXT: p[]: full-set, @RecursiveNoOffset(arg0, [4,5)){{$}}
437 ; CHECK-NEXT: size[]: empty-set, @RecursiveNoOffset(arg1, [4294967295,4294967296)){{$}}
438 ; CHECK-NEXT: acc[]: [0,4), @RecursiveNoOffset(arg2, [0,1)){{$}}
439 ; CHECK-NEXT: allocas uses:
440 ; CHECK-NOT: ]:
442 ; CHECK-LABEL: @RecursiveWithOffset{{$}}
443 ; CHECK-NEXT: args uses:
444 ; CHECK-NEXT: size[]: empty-set, @RecursiveWithOffset(arg0, [4294967295,4294967296)){{$}}
445 ; LOCAL-NEXT: acc[]: [0,4), @RecursiveWithOffset(arg1, [4,5)){{$}}
446 ; GLOBAL-NEXT: acc[]: full-set, @RecursiveWithOffset(arg1, [4,5)){{$}}
447 ; CHECK-NEXT: allocas uses:
448 ; CHECK-NOT: ]: