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