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