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