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