1; REQUIRES: aarch64-registered-target
2; REQUIRES: shell
3
4; RUN: llvm-as %s -o %t0.bc
5; RUN: llvm-as %S/Inputs/ipa.ll -o %t1.bc
6; RUN: llvm-link -disable-lazy-loading %t0.bc %t1.bc -o %t.combined.bc
7
8; RUN: opt -S -passes="print<stack-safety-local>" -disable-output %t.combined.bc 2>&1 | FileCheck %s --check-prefixes=CHECK,LOCAL
9
10; RUN: opt -S -passes="print-stack-safety" -disable-output %t.combined.bc 2>&1 | FileCheck %s --check-prefixes=CHECK,GLOBAL,NOLTO
11
12; Do an end-to-test using the new LTO API
13; TODO: Hideous llvm-lto2 invocation, add a --default-symbol-resolution to llvm-lto2?
14; RUN: opt -module-summary %s -o %t.summ0.bc
15; RUN: opt -module-summary %S/Inputs/ipa.ll -o %t.summ1.bc
16
17; RUN: llvm-dis %t.summ0.bc -o - > %t.ids.txt
18; RUN: llvm-dis %t.summ1.bc -o - >> %t.ids.txt
19
20; RUN: echo > %t.res.txt \
21; RUN:  -r %t.summ0.bc,ExternalCall, \
22; RUN:  -r %t.summ0.bc,f1,px \
23; RUN:  -r %t.summ0.bc,f2,px \
24; RUN:  -r %t.summ0.bc,f3,px \
25; RUN:  -r %t.summ0.bc,f4,px \
26; RUN:  -r %t.summ0.bc,f5,px \
27; RUN:  -r %t.summ0.bc,f6,px \
28; RUN:  -r %t.summ0.bc,f7,px \
29; RUN:  -r %t.summ0.bc,f8left,px \
30; RUN:  -r %t.summ0.bc,f8oobleft,px \
31; RUN:  -r %t.summ0.bc,f8oobright,px \
32; RUN:  -r %t.summ0.bc,f8right,px \
33; RUN:  -r %t.summ0.bc,InterposableCall,px \
34; RUN:  -r %t.summ0.bc,InterposableWrite1, \
35; RUN:  -r %t.summ0.bc,PreemptableCall,px \
36; RUN:  -r %t.summ0.bc,PreemptableWrite1, \
37; RUN:  -r %t.summ0.bc,PrivateCall,px \
38; RUN:  -r %t.summ0.bc,Rec2, \
39; RUN:  -r %t.summ0.bc,RecursiveNoOffset, \
40; RUN:  -r %t.summ0.bc,RecursiveWithOffset, \
41; RUN:  -r %t.summ0.bc,ReturnDependent, \
42; RUN:  -r %t.summ0.bc,TestCrossModuleConflict,px \
43; RUN:  -r %t.summ0.bc,TestCrossModuleOnce,px \
44; RUN:  -r %t.summ0.bc,TestCrossModuleTwice,px \
45; RUN:  -r %t.summ0.bc,TestCrossModuleWeak,px \
46; RUN:  -r %t.summ0.bc,TestRecursiveNoOffset,px \
47; RUN:  -r %t.summ0.bc,TestRecursiveWithOffset,px \
48; RUN:  -r %t.summ0.bc,TestUpdateArg,px \
49; RUN:  -r %t.summ0.bc,TwoArguments,px \
50; RUN:  -r %t.summ0.bc,TwoArgumentsOOBBoth,px \
51; RUN:  -r %t.summ0.bc,TwoArgumentsOOBOne,px \
52; RUN:  -r %t.summ0.bc,TwoArgumentsOOBOther,px \
53; RUN:  -r %t.summ0.bc,Weak,x \
54; RUN:  -r %t.summ0.bc,Write1, \
55; RUN:  -r %t.summ0.bc,Write1DiffModule,x \
56; RUN:  -r %t.summ0.bc,Write1Module0,px \
57; RUN:  -r %t.summ0.bc,Write1Private,x \
58; RUN:  -r %t.summ0.bc,Write1SameModule,x \
59; RUN:  -r %t.summ0.bc,Write1Weak,x \
60; RUN:  -r %t.summ0.bc,Write4_2, \
61; RUN:  -r %t.summ0.bc,Write4, \
62; RUN:  -r %t.summ0.bc,Write8, \
63; RUN:  -r %t.summ0.bc,WriteAndReturn8, \
64; RUN:  -r %t.summ1.bc,ExternalCall,px \
65; RUN:  -r %t.summ1.bc,InterposableWrite1,px \
66; RUN:  -r %t.summ1.bc,PreemptableWrite1,px \
67; RUN:  -r %t.summ1.bc,Rec0,px \
68; RUN:  -r %t.summ1.bc,Rec1,px \
69; RUN:  -r %t.summ1.bc,Rec2,px \
70; RUN:  -r %t.summ1.bc,RecursiveNoOffset,px \
71; RUN:  -r %t.summ1.bc,RecursiveWithOffset,px \
72; RUN:  -r %t.summ1.bc,ReturnAlloca,px \
73; RUN:  -r %t.summ1.bc,ReturnDependent,px \
74; RUN:  -r %t.summ1.bc,Weak,x \
75; RUN:  -r %t.summ1.bc,Write1,px \
76; RUN:  -r %t.summ1.bc,Write1DiffModule,px \
77; RUN:  -r %t.summ1.bc,Write1Module0,x \
78; RUN:  -r %t.summ1.bc,Write1Private,px \
79; RUN:  -r %t.summ1.bc,Write1SameModule,px \
80; RUN:  -r %t.summ1.bc,Write1Weak,px \
81; RUN:  -r %t.summ1.bc,Write4_2,px \
82; RUN:  -r %t.summ1.bc,Write4,px \
83; RUN:  -r %t.summ1.bc,Write8,px \
84; RUN:  -r %t.summ1.bc,WriteAndReturn8,px
85
86; RUN: llvm-lto2 run %t.summ0.bc %t.summ1.bc -o %t.lto -stack-safety-print -stack-safety-run -save-temps -thinlto-threads 1 -O0 \
87; RUN:  $(cat %t.res.txt) \
88; RUN:    2>&1 | FileCheck %s --check-prefixes=CHECK,GLOBAL,LTO
89
90; RUN: llvm-lto2 run %t.summ0.bc %t.summ1.bc -o %t.lto -stack-safety-run -thinlto-distributed-indexes -thinlto-threads 1 -O0 $(cat %t.res.txt)
91; RUN: (cat %t.ids.txt ; llvm-dis %t.summ1.bc.thinlto.bc -o -) | FileCheck --check-prefixes=INDEX %s
92
93; RUN: llvm-lto2 run %t.summ0.bc %t.summ1.bc -o %t-newpm.lto -use-new-pm -stack-safety-print -stack-safety-run -save-temps -thinlto-threads 1 -O0 \
94; RUN:  $(cat %t.res.txt) \
95; RUN:    2>&1 | FileCheck %s --check-prefixes=CHECK,GLOBAL,LTO
96
97; RUN: llvm-lto2 run %t.summ0.bc %t.summ1.bc -o %t-newpm.lto -stack-safety-run -thinlto-distributed-indexes -thinlto-threads 1 -O0 $(cat %t.res.txt)
98; RUN: (cat %t.ids.txt ; llvm-dis %t.summ1.bc.thinlto.bc -o -) | FileCheck --check-prefixes=INDEX %s
99
100target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
101target triple = "aarch64-unknown-linux"
102
103attributes #0 = { noinline sanitize_memtag "target-features"="+mte,+neon" }
104
105declare void @Write1(i8* %p)
106declare void @Write4(i8* %p)
107declare void @Write4_2(i8* %p, i8* %q)
108declare void @Write8(i8* %p)
109declare dso_local i8* @WriteAndReturn8(i8* %p)
110declare dso_local void @ExternalCall(i8* %p)
111declare void @PreemptableWrite1(i8* %p)
112declare void @InterposableWrite1(i8* %p)
113declare i8* @ReturnDependent(i8* %p)
114declare void @Rec2(i8* %p)
115declare void @RecursiveNoOffset(i32* %p, i32 %size, i32* %acc)
116declare void @RecursiveWithOffset(i32 %size, i32* %acc)
117declare void @Write1SameModule(i8* %p)
118declare void @Write1DiffModule(i8* %p)
119declare void @Write1Private(i8* %p)
120declare void @Write1Weak(i8* %p)
121
122; Basic out-of-bounds.
123define void @f1() #0 {
124; CHECK-LABEL: @f1 dso_preemptable{{$}}
125; CHECK-NEXT: args uses:
126; CHECK-NEXT: allocas uses:
127; LOCAL-NEXT: x[4]: empty-set, @Write8(arg0, [0,1)){{$}}
128; GLOBAL-NEXT: x[4]: [0,8), @Write8(arg0, [0,1)){{$}}
129; GLOBAL-NEXT: safe accesses:
130; CHECK-EMPTY:
131entry:
132  %x = alloca i32, align 4
133  %x1 = bitcast i32* %x to i8*
134  call void @Write8(i8* %x1)
135  ret void
136}
137
138; Basic in-bounds.
139define void @f2() #0 {
140; CHECK-LABEL: @f2 dso_preemptable{{$}}
141; CHECK-NEXT: args uses:
142; CHECK-NEXT: allocas uses:
143; LOCAL-NEXT: x[4]: empty-set, @Write1(arg0, [0,1)){{$}}
144; GLOBAL-NEXT: x[4]: [0,1), @Write1(arg0, [0,1)){{$}}
145; GLOBAL-NEXT: safe accesses:
146; CHECK-EMPTY:
147entry:
148  %x = alloca i32, align 4
149  %x1 = bitcast i32* %x to i8*
150  call void @Write1(i8* %x1)
151  ret void
152}
153
154; Another basic in-bounds.
155define void @f3() #0 {
156; CHECK-LABEL: @f3 dso_preemptable{{$}}
157; CHECK-NEXT: args uses:
158; CHECK-NEXT: allocas uses:
159; LOCAL-NEXT: x[4]: empty-set, @Write4(arg0, [0,1)){{$}}
160; GLOBAL-NEXT: x[4]: [0,4), @Write4(arg0, [0,1)){{$}}
161; GLOBAL-NEXT: safe accesses:
162; CHECK-EMPTY:
163entry:
164  %x = alloca i32, align 4
165  %x1 = bitcast i32* %x to i8*
166  call void @Write4(i8* %x1)
167  ret void
168}
169
170; In-bounds with offset.
171define void @f4() #0 {
172; CHECK-LABEL: @f4 dso_preemptable{{$}}
173; CHECK-NEXT: args uses:
174; CHECK-NEXT: allocas uses:
175; LOCAL-NEXT: x[4]: empty-set, @Write1(arg0, [1,2)){{$}}
176; GLOBAL-NEXT: x[4]: [1,2), @Write1(arg0, [1,2)){{$}}
177; GLOBAL-NEXT: safe accesses:
178; CHECK-EMPTY:
179entry:
180  %x = alloca i32, align 4
181  %x1 = bitcast i32* %x to i8*
182  %x2 = getelementptr i8, i8* %x1, i64 1
183  call void @Write1(i8* %x2)
184  ret void
185}
186
187; Out-of-bounds with offset.
188define void @f5() #0 {
189; CHECK-LABEL: @f5 dso_preemptable{{$}}
190; CHECK-NEXT: args uses:
191; CHECK-NEXT: allocas uses:
192; LOCAL-NEXT: empty-set, @Write4(arg0, [1,2)){{$}}
193; GLOBAL-NEXT: [1,5), @Write4(arg0, [1,2)){{$}}
194; GLOBAL-NEXT: safe accesses:
195; CHECK-EMPTY:
196entry:
197  %x = alloca i32, align 4
198  %x1 = bitcast i32* %x to i8*
199  %x2 = getelementptr i8, i8* %x1, i64 1
200  call void @Write4(i8* %x2)
201  ret void
202}
203
204; External call.
205define void @f6() #0 {
206; CHECK-LABEL: @f6 dso_preemptable{{$}}
207; CHECK-NEXT: args uses:
208; CHECK-NEXT: allocas uses:
209; LOCAL-NEXT: x[4]: empty-set, @ExternalCall(arg0, [0,1)){{$}}
210; GLOBAL-NEXT: x[4]: full-set, @ExternalCall(arg0, [0,1)){{$}}
211; GLOBAL-NEXT: safe accesses:
212; CHECK-EMPTY:
213entry:
214  %x = alloca i32, align 4
215  %x1 = bitcast i32* %x to i8*
216  call void @ExternalCall(i8* %x1)
217  ret void
218}
219
220; Call to dso_preemptable function
221define void @PreemptableCall() #0 {
222; CHECK-LABEL: @PreemptableCall dso_preemptable{{$}}
223; CHECK-NEXT: args uses:
224; CHECK-NEXT: allocas uses:
225; LOCAL-NEXT: x[4]: empty-set, @PreemptableWrite1(arg0, [0,1)){{$}}
226; GLOBAL-NEXT: x[4]: full-set, @PreemptableWrite1(arg0, [0,1)){{$}}
227; GLOBAL-NEXT: safe accesses:
228; CHECK-EMPTY:
229entry:
230  %x = alloca i32, align 4
231  %x1 = bitcast i32* %x to i8*
232  call void @PreemptableWrite1(i8* %x1)
233  ret void
234}
235
236; Call to function with interposable linkage
237define void @InterposableCall() #0 {
238; CHECK-LABEL: @InterposableCall dso_preemptable{{$}}
239; CHECK-NEXT: args uses:
240; CHECK-NEXT: allocas uses:
241; LOCAL-NEXT: x[4]: empty-set, @InterposableWrite1(arg0, [0,1)){{$}}
242; NOLTO-NEXT: x[4]: full-set, @InterposableWrite1(arg0, [0,1)){{$}}
243; LTO-NEXT: x[4]: [0,1), @InterposableWrite1(arg0, [0,1)){{$}}
244; GLOBAL-NEXT: safe accesses:
245; CHECK-EMPTY:
246entry:
247  %x = alloca i32, align 4
248  %x1 = bitcast i32* %x to i8*
249  call void @InterposableWrite1(i8* %x1)
250  ret void
251}
252
253; Call to function with private linkage
254define void @PrivateCall() #0 {
255; CHECK-LABEL: @PrivateCall dso_preemptable{{$}}
256; CHECK-NEXT: args uses:
257; CHECK-NEXT: allocas uses:
258; LOCAL-NEXT: x[4]: empty-set, @PrivateWrite1(arg0, [0,1)){{$}}
259; GLOBAL-NEXT: x[4]: [0,1), @PrivateWrite1(arg0, [0,1)){{$}}
260; GLOBAL-NEXT: safe accesses:
261; CHECK-EMPTY:
262entry:
263  %x = alloca i32, align 4
264  %x1 = bitcast i32* %x to i8*
265  call void @PrivateWrite1(i8* %x1)
266  ret void
267}
268
269define private void @PrivateWrite1(i8* %p) #0 {
270; CHECK-LABEL: @PrivateWrite1{{$}}
271; CHECK-NEXT: args uses:
272; CHECK-NEXT: p[]: [0,1){{$}}
273; CHECK-NEXT: allocas uses:
274; GLOBAL-NEXT: safe accesses:
275; GLOBAL-NEXT: store i8 0, i8* %p, align 1
276; CHECK-EMPTY:
277entry:
278  store i8 0, i8* %p, align 1
279  ret void
280}
281
282; Caller returns a dependent value.
283; FIXME: alloca considered unsafe even if the return value is unused.
284define void @f7() #0 {
285; CHECK-LABEL: @f7 dso_preemptable{{$}}
286; CHECK-NEXT: args uses:
287; CHECK-NEXT: allocas uses:
288; LOCAL-NEXT: x[4]: empty-set, @ReturnDependent(arg0, [0,1)){{$}}
289; GLOBAL-NEXT: x[4]: full-set, @ReturnDependent(arg0, [0,1)){{$}}
290; GLOBAL-NEXT: safe accesses:
291; CHECK-EMPTY:
292entry:
293  %x = alloca i32, align 4
294  %x1 = bitcast i32* %x to i8*
295  %x2 = call i8* @ReturnDependent(i8* %x1)
296  ret void
297}
298
299define void @f8left() #0 {
300; CHECK-LABEL: @f8left dso_preemptable{{$}}
301; CHECK-NEXT: args uses:
302; CHECK-NEXT: allocas uses:
303; LOCAL-NEXT: x[8]: empty-set, @Rec2(arg0, [2,3)){{$}}
304; GLOBAL-NEXT: x[8]: [0,4), @Rec2(arg0, [2,3)){{$}}
305; GLOBAL-NEXT: safe accesses:
306; CHECK-EMPTY:
307entry:
308  %x = alloca i64, align 4
309  %x1 = bitcast i64* %x to i8*
310  %x2 = getelementptr i8, i8* %x1, i64 2
311; 2 + [-2, 2) = [0, 4) => OK
312  call void @Rec2(i8* %x2)
313  ret void
314}
315
316define void @f8right() #0 {
317; CHECK-LABEL: @f8right dso_preemptable{{$}}
318; CHECK-NEXT: args uses:
319; CHECK-NEXT: allocas uses:
320; LOCAL-NEXT: x[8]: empty-set, @Rec2(arg0, [6,7)){{$}}
321; GLOBAL-NEXT: x[8]: [4,8), @Rec2(arg0, [6,7)){{$}}
322; GLOBAL-NEXT: safe accesses:
323; CHECK-EMPTY:
324entry:
325  %x = alloca i64, align 4
326  %x1 = bitcast i64* %x to i8*
327  %x2 = getelementptr i8, i8* %x1, i64 6
328; 6 + [-2, 2) = [4, 8) => OK
329  call void @Rec2(i8* %x2)
330  ret void
331}
332
333define void @f8oobleft() #0 {
334; CHECK-LABEL: @f8oobleft dso_preemptable{{$}}
335; CHECK-NEXT: args uses:
336; CHECK-NEXT: allocas uses:
337; LOCAL-NEXT: x[8]: empty-set, @Rec2(arg0, [1,2)){{$}}
338; GLOBAL-NEXT: x[8]: [-1,3), @Rec2(arg0, [1,2)){{$}}
339; GLOBAL-NEXT: safe accesses:
340; CHECK-EMPTY:
341entry:
342  %x = alloca i64, align 4
343  %x1 = bitcast i64* %x to i8*
344  %x2 = getelementptr i8, i8* %x1, i64 1
345; 1 + [-2, 2) = [-1, 3) => NOT OK
346  call void @Rec2(i8* %x2)
347  ret void
348}
349
350define void @f8oobright() #0 {
351; CHECK-LABEL: @f8oobright dso_preemptable{{$}}
352; CHECK-NEXT: args uses:
353; CHECK-NEXT: allocas uses:
354; LOCAL-NEXT: x[8]: empty-set, @Rec2(arg0, [7,8)){{$}}
355; GLOBAL-NEXT: x[8]: [5,9), @Rec2(arg0, [7,8)){{$}}
356; GLOBAL-NEXT: safe accesses:
357; CHECK-EMPTY:
358entry:
359  %x = alloca i64, align 4
360  %x1 = bitcast i64* %x to i8*
361  %x2 = getelementptr i8, i8* %x1, i64 7
362; 7 + [-2, 2) = [5, 9) => NOT OK
363  call void @Rec2(i8* %x2)
364  ret void
365}
366
367define void @TwoArguments() #0 {
368; CHECK-LABEL: @TwoArguments dso_preemptable{{$}}
369; CHECK-NEXT: args uses:
370; CHECK-NEXT: allocas uses:
371; LOCAL-NEXT: x[8]: empty-set, @Write4_2(arg0, [4,5)), @Write4_2(arg1, [0,1)){{$}}
372; GLOBAL-NEXT: x[8]: [0,8), @Write4_2(arg0, [4,5)), @Write4_2(arg1, [0,1)){{$}}
373; GLOBAL-NEXT: safe accesses:
374; CHECK-EMPTY:
375entry:
376  %x = alloca i64, align 4
377  %x1 = bitcast i64* %x to i8*
378  %x2 = getelementptr i8, i8* %x1, i64 4
379  call void @Write4_2(i8* %x2, i8* %x1)
380  ret void
381}
382
383define void @TwoArgumentsOOBOne() #0 {
384; CHECK-LABEL: @TwoArgumentsOOBOne dso_preemptable{{$}}
385; CHECK-NEXT: args uses:
386; CHECK-NEXT: allocas uses:
387; LOCAL-NEXT: x[8]: empty-set, @Write4_2(arg0, [5,6)), @Write4_2(arg1, [0,1)){{$}}
388; GLOBAL-NEXT: x[8]: [0,9), @Write4_2(arg0, [5,6)), @Write4_2(arg1, [0,1)){{$}}
389; GLOBAL-NEXT: safe accesses:
390; CHECK-EMPTY:
391entry:
392  %x = alloca i64, align 4
393  %x1 = bitcast i64* %x to i8*
394  %x2 = getelementptr i8, i8* %x1, i64 5
395  call void @Write4_2(i8* %x2, i8* %x1)
396  ret void
397}
398
399define void @TwoArgumentsOOBOther() #0 {
400; CHECK-LABEL: @TwoArgumentsOOBOther dso_preemptable{{$}}
401; CHECK-NEXT: args uses:
402; CHECK-NEXT: allocas uses:
403; LOCAL-NEXT: x[8]: empty-set, @Write4_2(arg0, [4,5)), @Write4_2(arg1, [-1,0)){{$}}
404; GLOBAL-NEXT: x[8]: [-1,8), @Write4_2(arg0, [4,5)), @Write4_2(arg1, [-1,0)){{$}}
405; GLOBAL-NEXT: safe accesses:
406; CHECK-EMPTY:
407entry:
408  %x = alloca i64, align 4
409  %x0 = bitcast i64* %x to i8*
410  %x1 = getelementptr i8, i8* %x0, i64 -1
411  %x2 = getelementptr i8, i8* %x0, i64 4
412  call void @Write4_2(i8* %x2, i8* %x1)
413  ret void
414}
415
416define void @TwoArgumentsOOBBoth() #0 {
417; CHECK-LABEL: @TwoArgumentsOOBBoth dso_preemptable{{$}}
418; CHECK-NEXT: args uses:
419; CHECK-NEXT: allocas uses:
420; LOCAL-NEXT: x[8]: empty-set, @Write4_2(arg0, [5,6)), @Write4_2(arg1, [-1,0)){{$}}
421; GLOBAL-NEXT: x[8]: [-1,9), @Write4_2(arg0, [5,6)), @Write4_2(arg1, [-1,0)){{$}}
422; GLOBAL-NEXT: safe accesses:
423; CHECK-EMPTY:
424entry:
425  %x = alloca i64, align 4
426  %x0 = bitcast i64* %x to i8*
427  %x1 = getelementptr i8, i8* %x0, i64 -1
428  %x2 = getelementptr i8, i8* %x0, i64 5
429  call void @Write4_2(i8* %x2, i8* %x1)
430  ret void
431}
432
433define i32 @TestRecursiveNoOffset(i32* %p, i32 %size) #0 {
434; CHECK-LABEL: @TestRecursiveNoOffset dso_preemptable{{$}}
435; CHECK-NEXT: args uses:
436; LOCAL-NEXT: p[]: empty-set, @RecursiveNoOffset(arg0, [0,1)){{$}}
437; GLOBAL-NEXT: p[]: full-set, @RecursiveNoOffset(arg0, [0,1)){{$}}
438; CHECK-NEXT: allocas uses:
439; CHECK-NEXT: sum[4]: [0,4), @RecursiveNoOffset(arg2, [0,1)){{$}}
440; GLOBAL-NEXT: safe accesses:
441; GLOBAL-NEXT: store i32 0, i32* %sum, align 4
442; GLOBAL-NEXT: %1 = load i32, i32* %sum, align 4
443; CHECK-EMPTY:
444entry:
445  %sum = alloca i32, align 4
446  %0 = bitcast i32* %sum to i8*
447  store i32 0, i32* %sum, align 4
448  call void @RecursiveNoOffset(i32* %p, i32 %size, i32* %sum)
449  %1 = load i32, i32* %sum, align 4
450  ret i32 %1
451}
452
453define void @TestRecursiveWithOffset(i32 %size) #0 {
454; CHECK-LABEL: @TestRecursiveWithOffset dso_preemptable{{$}}
455; CHECK-NEXT: args uses:
456; CHECK-NEXT: allocas uses:
457; LOCAL-NEXT: sum[64]: empty-set, @RecursiveWithOffset(arg1, [0,1)){{$}}
458; GLOBAL-NEXT: sum[64]: full-set, @RecursiveWithOffset(arg1, [0,1)){{$}}
459; GLOBAL-NEXT: safe accesses:
460; CHECK-EMPTY:
461entry:
462  %sum = alloca i32, i64 16, align 4
463  call void @RecursiveWithOffset(i32 %size, i32* %sum)
464  ret void
465}
466
467; FIXME: IPA should detect that access is safe
468define void @TestUpdateArg() #0 {
469; CHECK-LABEL: @TestUpdateArg dso_preemptable{{$}}
470; CHECK-NEXT: args uses:
471; CHECK-NEXT: allocas uses:
472; LOCAL-NEXT: x[16]: empty-set, @WriteAndReturn8(arg0, [0,1)){{$}}
473; GLOBAL-NEXT: x[16]: full-set, @WriteAndReturn8(arg0, [0,1)){{$}}
474; GLOBAL-NEXT: safe accesses:
475; CHECK-EMPTY:
476entry:
477  %x = alloca i8, i64 16, align 4
478  %0 = call i8* @WriteAndReturn8(i8* %x)
479  ret void
480}
481
482define void @TestCrossModuleOnce() #0 {
483; CHECK-DAG: @TestCrossModuleOnce dso_preemptable{{$}}
484; CHECK-NEXT: args uses:
485; CHECK-NEXT: allocas uses:
486; LOCAL-NEXT: y[1]: empty-set, @Write1SameModule(arg0, [0,1)){{$}}
487; GLOBAL-NEXT: y[1]: [0,1), @Write1SameModule(arg0, [0,1)){{$}}
488; GLOBAL-NEXT: safe accesses:
489; CHECK-EMPTY:
490entry:
491  %y = alloca i8, align 4
492  call void @Write1SameModule(i8* %y)
493  ret void
494}
495
496define void @TestCrossModuleTwice() #0 {
497; CHECK-DAG: @TestCrossModuleTwice dso_preemptable{{$}}
498; CHECK-NEXT: args uses:
499; CHECK-NEXT: allocas uses:
500; LOCAL-NEXT: z[1]: empty-set, @Write1DiffModule(arg0, [0,1)){{$}}
501; GLOBAL-NEXT: z[1]: [0,1), @Write1DiffModule(arg0, [0,1)){{$}}
502; GLOBAL-NEXT: safe accesses:
503; CHECK-EMPTY:
504entry:
505  %z = alloca i8, align 4
506  call void @Write1DiffModule(i8* %z)
507  ret void
508}
509
510define void @TestCrossModuleConflict() #0 {
511; CHECK-DAG: @TestCrossModuleConflict dso_preemptable{{$}}
512; CHECK-NEXT: args uses:
513; CHECK-NEXT: allocas uses:
514; LOCAL-NEXT: x[1]: empty-set, @Write1Private(arg0, [0,1)){{$}}
515; GLOBAL-NEXT: x[1]: [-1,0), @Write1Private(arg0, [0,1)){{$}}
516; GLOBAL-NEXT: safe accesses:
517; CHECK-EMPTY:
518entry:
519  %x = alloca i8, align 4
520  call void @Write1Private(i8* %x)
521  ret void
522}
523
524; FIXME: LTO should match NOLTO
525define void @TestCrossModuleWeak() #0 {
526; CHECK-DAG: @TestCrossModuleWeak dso_preemptable{{$}}
527; CHECK-NEXT: args uses:
528; CHECK-NEXT: allocas uses:
529; LOCAL-NEXT: x[1]: empty-set, @Write1Weak(arg0, [0,1)){{$}}
530; NOLTO-NEXT: x[1]: [1,2), @Write1Weak(arg0, [0,1)){{$}}
531; LTO-NEXT: x[1]: full-set, @Write1Weak(arg0, [0,1)){{$}}
532; GLOBAL-NEXT: safe accesses:
533; CHECK-EMPTY:
534entry:
535  %x = alloca i8, align 4
536  call void @Write1Weak(i8* %x)
537  ret void
538}
539
540define private dso_local void @Private(i8* %p) #0 {
541entry:
542  %p1 = getelementptr i8, i8* %p, i64 1
543  store i8 0, i8* %p1, align 1
544  ret void
545}
546
547define dso_local void @Write1Module0(i8* %p) #0 {
548entry:
549  store i8 0, i8* %p, align 1
550  ret void
551}
552
553define dso_local void @Weak(i8* %p) #0 {
554entry:
555  %p1 = getelementptr i8, i8* %p, i64 1
556  store i8 0, i8* %p1, align 1
557  ret void
558}
559
560; The rest is from Inputs/ipa.ll
561
562; CHECK-LABEL: @Write1{{$}}
563; CHECK-NEXT: args uses:
564; CHECK-NEXT: p[]: [0,1){{$}}
565; CHECK-NEXT: allocas uses:
566; GLOBAL-NEXT: safe accesses:
567; GLOBAL-NEXT: store i8 0, i8* %p, align 1
568; CHECK-EMPTY:
569
570; CHECK-LABEL: @Write4{{$}}
571; CHECK-NEXT: args uses:
572; CHECK-NEXT: p[]: [0,4){{$}}
573; CHECK-NEXT: allocas uses:
574; GLOBAL-NEXT: safe accesses:
575; GLOBAL-NEXT: store i32 0, i32* %0, align 1
576; CHECK-EMPTY:
577
578; CHECK-LABEL: @Write4_2{{$}}
579; CHECK-NEXT: args uses:
580; CHECK-NEXT: p[]: [0,4){{$}}
581; CHECK-NEXT: q[]: [0,4){{$}}
582; CHECK-NEXT: allocas uses:
583; GLOBAL-NEXT: safe accesses:
584; GLOBAL-NEXT: store i32 0, i32* %0, align 1
585; GLOBAL-NEXT: store i32 0, i32* %1, align 1
586; CHECK-EMPTY:
587
588; CHECK-LABEL: @Write8{{$}}
589; CHECK-NEXT: args uses:
590; CHECK-NEXT: p[]: [0,8){{$}}
591; CHECK-NEXT: allocas uses:
592; GLOBAL-NEXT: safe accesses:
593; GLOBAL-NEXT: store i64 0, i64* %0, align 1
594; CHECK-EMPTY:
595
596; CHECK-LABEL: @WriteAndReturn8{{$}}
597; CHECK-NEXT: args uses:
598; CHECK-NEXT: p[]: full-set{{$}}
599; CHECK-NEXT: allocas uses:
600; GLOBAL-NEXT: safe accesses:
601; GLOBAL-NEXT: store i8 0, i8* %p, align 1
602; CHECK-EMPTY:
603
604; CHECK-LABEL: @PreemptableWrite1 dso_preemptable{{$}}
605; CHECK-NEXT: args uses:
606; CHECK-NEXT: p[]: [0,1){{$}}
607; CHECK-NEXT: allocas uses:
608; GLOBAL-NEXT: safe accesses:
609; GLOBAL-NEXT: store i8 0, i8* %p, align 1
610; CHECK-EMPTY:
611
612; CHECK-LABEL: @InterposableWrite1 interposable{{$}}
613; CHECK-NEXT: args uses:
614; CHECK-NEXT: p[]: [0,1){{$}}
615; CHECK-NEXT: allocas uses:
616; GLOBAL-NEXT: safe accesses:
617; GLOBAL-NEXT: store i8 0, i8* %p, align 1
618; CHECK-EMPTY:
619
620; CHECK-LABEL: @ReturnDependent{{$}}
621; CHECK-NEXT: args uses:
622; CHECK-NEXT: p[]: full-set{{$}}
623; CHECK-NEXT: allocas uses:
624; GLOBAL-NEXT: safe accesses:
625; CHECK-EMPTY:
626
627; CHECK-LABEL: @Rec0{{$}}
628; CHECK-NEXT: args uses:
629; LOCAL-NEXT: p[]: empty-set, @Write4(arg0, [2,3)){{$}}
630; GLOBAL-NEXT: p[]: [2,6)
631; CHECK-NEXT: allocas uses:
632; GLOBAL-NEXT: safe accesses:
633; CHECK-EMPTY:
634
635; CHECK-LABEL: @Rec1{{$}}
636; CHECK-NEXT: args uses:
637; LOCAL-NEXT: p[]: empty-set, @Rec0(arg0, [1,2)){{$}}
638; GLOBAL-NEXT: p[]: [3,7)
639; CHECK-NEXT: allocas uses:
640; GLOBAL-NEXT: safe accesses:
641; CHECK-EMPTY:
642
643; CHECK-LABEL: @Rec2{{$}}
644; CHECK-NEXT: args uses:
645; LOCAL-NEXT: p[]: empty-set, @Rec1(arg0, [-5,-4)){{$}}
646; GLOBAL-NEXT: p[]: [-2,2)
647; CHECK-NEXT: allocas uses:
648; GLOBAL-NEXT: safe accesses:
649; CHECK-EMPTY:
650
651; CHECK-LABEL: @RecursiveNoOffset{{$}}
652; CHECK-NEXT: args uses:
653; LOCAL-NEXT: p[]: [0,4), @RecursiveNoOffset(arg0, [4,5)){{$}}
654; GLOBAL-NEXT: p[]: full-set, @RecursiveNoOffset(arg0, [4,5)){{$}}
655; CHECK-NEXT: acc[]: [0,4), @RecursiveNoOffset(arg2, [0,1)){{$}}
656; CHECK-NEXT: allocas uses:
657; GLOBAL-NEXT: safe accesses:
658; GLOBAL-NEXT: %0 = load i32, i32* %p, align 4
659; GLOBAL-NEXT: %1 = load i32, i32* %acc, align 4
660; GLOBAL-NEXT: store i32 %add, i32* %acc, align 4
661; CHECK-EMPTY:
662
663; CHECK-LABEL: @RecursiveWithOffset{{$}}
664; CHECK-NEXT: args uses:
665; LOCAL-NEXT: acc[]: [0,4), @RecursiveWithOffset(arg1, [4,5)){{$}}
666; GLOBAL-NEXT: acc[]: full-set, @RecursiveWithOffset(arg1, [4,5)){{$}}
667; CHECK-NEXT: allocas uses:
668; GLOBAL-NEXT: safe accesses:
669; GLOBAL-NEXT: store i32 0, i32* %acc, align 4
670; CHECK-EMPTY:
671
672; CHECK-LABEL: @ReturnAlloca
673; CHECK-NEXT: args uses:
674; CHECK-NEXT: allocas uses:
675; CHECK-NEXT: x[8]: full-set
676; GLOBAL-NEXT: safe accesses:
677; CHECK-EMPTY:
678
679; INDEX-LABEL: ^0 = module:
680; INDEX-DAG: name: "ReturnDependent"{{.*}} guid = [[ReturnDependent:[-0-9]+]]
681; INDEX-DAG: name: "Private"{{.*}} guid = [[Private:[-0-9]+]]
682; INDEX-DAG: name: "TwoArgumentsOOBOther"{{.*}} guid = [[TwoArgumentsOOBOther:[-0-9]+]]
683; INDEX-DAG: name: "Rec2"{{.*}} guid = [[Rec2:[-0-9]+]]
684; INDEX-DAG: name: "f1"{{.*}} guid = [[f1:[-0-9]+]]
685; INDEX-DAG: name: "PrivateWrite1"{{.*}} guid = [[PrivateWrite1:[-0-9]+]]
686; INDEX-DAG: name: "TestRecursiveNoOffset"{{.*}} guid = [[TestRecursiveNoOffset:[-0-9]+]]
687; INDEX-DAG: name: "f8left"{{.*}} guid = [[f8left:[-0-9]+]]
688; INDEX-DAG: name: "Write4"{{.*}} guid = [[Write4:[-0-9]+]]
689; INDEX-DAG: name: "f7"{{.*}} guid = [[f7:[-0-9]+]]
690; INDEX-DAG: name: "Write1SameModule"{{.*}} guid = [[Write1SameModule:[-0-9]+]]
691; INDEX-DAG: name: "Write8"{{.*}} guid = [[Write8:[-0-9]+]]
692; INDEX-DAG: name: "TwoArgumentsOOBOne"{{.*}} guid = [[TwoArgumentsOOBOne:[-0-9]+]]
693; INDEX-DAG: name: "f3"{{.*}} guid = [[f3:[-0-9]+]]
694; INDEX-DAG: name: "f8right"{{.*}} guid = [[f8right:[-0-9]+]]
695; INDEX-DAG: name: "Write4_2"{{.*}} guid = [[Write4_2:[-0-9]+]]
696; INDEX-DAG: name: "RecursiveWithOffset"{{.*}} guid = [[RecursiveWithOffset:[-0-9]+]]
697; INDEX-DAG: name: "Weak"{{.*}} guid = [[Weak:[-0-9]+]]
698; INDEX-DAG: name: "Write1Private"{{.*}} guid = [[Write1Private:[-0-9]+]]
699; INDEX-DAG: name: "TestUpdateArg"{{.*}} guid = [[TestUpdateArg:[-0-9]+]]
700; INDEX-DAG: name: "TestCrossModuleTwice"{{.*}} guid = [[TestCrossModuleTwice:[-0-9]+]]
701; INDEX-DAG: name: "TestCrossModuleWeak"{{.*}} guid = [[TestCrossModuleWeak:[-0-9]+]]
702; INDEX-DAG: name: "f2"{{.*}} guid = [[f2:[-0-9]+]]
703; INDEX-DAG: name: "PrivateCall"{{.*}} guid = [[PrivateCall:[-0-9]+]]
704; INDEX-DAG: name: "TestRecursiveWithOffset"{{.*}} guid = [[TestRecursiveWithOffset:[-0-9]+]]
705; INDEX-DAG: name: "f8oobleft"{{.*}} guid = [[f8oobleft:[-0-9]+]]
706; INDEX-DAG: name: "InterposableWrite1"{{.*}} guid = [[InterposableWrite1:[-0-9]+]]
707; INDEX-DAG: name: "f4"{{.*}} guid = [[f4:[-0-9]+]]
708; INDEX-DAG: name: "TestCrossModuleConflict"{{.*}} guid = [[TestCrossModuleConflict:[-0-9]+]]
709; INDEX-DAG: name: "RecursiveNoOffset"{{.*}} guid = [[RecursiveNoOffset:[-0-9]+]]
710; INDEX-DAG: name: "TwoArgumentsOOBBoth"{{.*}} guid = [[TwoArgumentsOOBBoth:[-0-9]+]]
711; INDEX-DAG: name: "f5"{{.*}} guid = [[f5:[-0-9]+]]
712; INDEX-DAG: name: "f6"{{.*}} guid = [[f6:[-0-9]+]]
713; INDEX-DAG: name: "Write1Weak"{{.*}} guid = [[Write1Weak:[-0-9]+]]
714; INDEX-DAG: name: "Write1"{{.*}} guid = [[Write1:[-0-9]+]]
715; INDEX-DAG: name: "PreemptableWrite1"{{.*}} guid = [[PreemptableWrite1:[-0-9]+]]
716; INDEX-DAG: name: "f8oobright"{{.*}} guid = [[f8oobright:[-0-9]+]]
717; INDEX-DAG: name: "InterposableCall"{{.*}} guid = [[InterposableCall:[-0-9]+]]
718; INDEX-DAG: name: "TestCrossModuleOnce"{{.*}} guid = [[TestCrossModuleOnce:[-0-9]+]]
719; INDEX-DAG: name: "WriteAndReturn8"{{.*}} guid = [[WriteAndReturn8:[-0-9]+]]
720; INDEX-DAG: name: "TwoArguments"{{.*}} guid = [[TwoArguments:[-0-9]+]]
721; INDEX-DAG: name: "Write1Module0"{{.*}} guid = [[Write1Module0:[-0-9]+]]
722; INDEX-DAG: name: "PreemptableCall"{{.*}} guid = [[PreemptableCall:[-0-9]+]]
723; INDEX-DAG: name: "Write1DiffModule"{{.*}} guid = [[Write1DiffModule:[-0-9]+]]
724; INDEX-DAG: name: "ExternalCall"{{.*}} guid = [[ExternalCall:[-0-9]+]]
725; INDEX-LABEL: = blockcount:
726
727; INDEX-LABEL: ^0 = module:
728; INDEX-DAG: name: "ReturnDependent"{{.*}} guid = [[ReturnDependent:[-0-9]+]]
729; INDEX-DAG: name: "Rec0"{{.*}} guid = [[Rec0:[-0-9]+]]
730; INDEX-DAG: name: "Rec2"{{.*}} guid = [[Rec2:[-0-9]+]]
731; INDEX-DAG: name: "Write4"{{.*}} guid = [[Write4:[-0-9]+]]
732; INDEX-DAG: name: "Write1SameModule"{{.*}} guid = [[Write1SameModule:[-0-9]+]]
733; INDEX-DAG: name: "Write8"{{.*}} guid = [[Write8:[-0-9]+]]
734; INDEX-DAG: name: "Write4_2"{{.*}} guid = [[Write4_2:[-0-9]+]]
735; INDEX-DAG: name: "RecursiveWithOffset"{{.*}} guid = [[RecursiveWithOffset:[-0-9]+]]
736; INDEX-DAG: name: "Weak"{{.*}} guid = [[Weak:[-0-9]+]]
737; INDEX-DAG: name: "Write1Private"{{.*}} guid = [[Write1Private:[-0-9]+]]
738; INDEX-DAG: name: "InterposableWrite1"{{.*}} guid = [[InterposableWrite1:[-0-9]+]]
739; INDEX-DAG: name: "Private"{{.*}} guid = [[Private:[-0-9]+]]
740; INDEX-DAG: name: "Rec1"{{.*}} guid = [[Rec1:[-0-9]+]]
741; INDEX-DAG: name: "RecursiveNoOffset"{{.*}} guid = [[RecursiveNoOffset:[-0-9]+]]
742; INDEX-DAG: name: "Write1Weak"{{.*}} guid = [[Write1Weak:[-0-9]+]]
743; INDEX-DAG: name: "Write1"{{.*}} guid = [[Write1:[-0-9]+]]
744; INDEX-DAG: name: "PreemptableWrite1"{{.*}} guid = [[PreemptableWrite1:[-0-9]+]]
745; INDEX-DAG: name: "WriteAndReturn8"{{.*}} guid = [[WriteAndReturn8:[-0-9]+]]
746; INDEX-DAG: name: "Write1Module0"{{.*}} guid = [[Write1Module0:[-0-9]+]]
747; INDEX-DAG: name: "Write1DiffModule"{{.*}} guid = [[Write1DiffModule:[-0-9]+]]
748; INDEX-DAG: name: "ExternalCall"{{.*}} guid = [[ExternalCall:[-0-9]+]]
749; INDEX-DAG: name: "ReturnAlloca"{{.*}} guid = [[ReturnAlloca:[-0-9]+]]
750; INDEX-LABEL: = blockcount:
751
752; INDEX-LABEL: ^0 = module:
753; INDEX-DAG: guid: [[ReturnDependent]], {{.*}}, funcFlags: ({{.*}}))))
754; INDEX-DAG: guid: [[Rec0]], {{.*}}, params: ((param: 0, offset: [2, 5])))))
755; INDEX-DAG: guid: [[Rec2]], {{.*}}, params: ((param: 0, offset: [-2, 1])))))
756; INDEX-DAG: guid: [[Write4]], {{.*}}, params: ((param: 0, offset: [0, 3])))))
757; INDEX-DAG: guid: [[Write1SameModule]], {{.*}}, params: ((param: 0, offset: [0, 0])))))
758; INDEX-DAG: guid: [[Write8]], {{.*}}, params: ((param: 0, offset: [0, 7])))))
759; INDEX-DAG: guid: [[Write4_2]], {{.*}}, params: ((param: 0, offset: [0, 3]), (param: 1, offset: [0, 3])))))
760; INDEX-DAG: guid: [[RecursiveWithOffset]], {{.*}}, calls: ((callee: ^{{[0-9]+}})))))
761; INDEX-DAG: guid: [[Weak]], {{.*}}, funcFlags: ({{.*}}))))
762; INDEX-DAG: guid: [[Write1Private]], {{.*}}, params: ((param: 0, offset: [-1, -1])))))
763; INDEX-DAG: guid: [[InterposableWrite1]], {{.*}}, params: ((param: 0, offset: [0, 0])))))
764; INDEX-DAG: guid: [[Private]], {{.*}}, params: ((param: 0, offset: [-1, -1])))))
765; INDEX-DAG: guid: [[Rec1]], {{.*}}, params: ((param: 0, offset: [3, 6])))))
766; INDEX-DAG: guid: [[RecursiveNoOffset]], {{.*}}, params: ((param: 2, offset: [0, 3])))))
767; INDEX-DAG: guid: [[Write1Weak]], {{.*}}, calls: ((callee: ^{{[0-9]+}})))))
768; INDEX-DAG: guid: [[Write1]], {{.*}}, params: ((param: 0, offset: [0, 0])))))
769; INDEX-DAG: guid: [[PreemptableWrite1]], {{.*}}, funcFlags: ({{.*}}))))
770; INDEX-DAG: guid: [[WriteAndReturn8]], {{.*}}, funcFlags: ({{.*}}))))
771; INDEX-DAG: guid: [[Write1DiffModule]], {{.*}}, funcFlags: ({{.*}}))))
772; INDEX-DAG: guid: [[ReturnAlloca]], {{.*}}, insts: 2)))
773; INDEX-LABEL: blockcount:
774