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