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