1; RUN: opt -S -analyze -stack-safety-local < %s | FileCheck %s --check-prefixes=CHECK,LOCAL
2; RUN: opt -S -passes="print<stack-safety-local>" -disable-output < %s 2>&1 | FileCheck %s --check-prefixes=CHECK,LOCAL
3; RUN: opt -S -analyze -stack-safety < %s | FileCheck %s --check-prefixes=CHECK,GLOBAL
4; RUN: opt -S -passes="print-stack-safety" -disable-output < %s 2>&1 | FileCheck %s --check-prefixes=CHECK,GLOBAL
5
6target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
7target triple = "x86_64-unknown-linux-gnu"
8
9@sink = global i8* null, align 8
10
11declare void @llvm.memset.p0i8.i32(i8* %dest, i8 %val, i32 %len, i1 %isvolatile)
12declare void @llvm.memcpy.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 %len, i1 %isvolatile)
13declare void @llvm.memmove.p0i8.p0i8.i32(i8* %dest, i8* %src, i32 %len, i1 %isvolatile)
14
15; Address leaked.
16define void @LeakAddress() {
17; CHECK-LABEL: @LeakAddress dso_preemptable{{$}}
18; CHECK-NEXT: args uses:
19; CHECK-NEXT: allocas uses:
20; CHECK-NEXT: x[4]: full-set{{$}}
21; CHECK-NOT: ]:
22entry:
23  %x = alloca i32, align 4
24  %x1 = bitcast i32* %x to i8*
25  store i8* %x1, i8** @sink, align 8
26  ret void
27}
28
29define void @StoreInBounds() {
30; CHECK-LABEL: @StoreInBounds dso_preemptable{{$}}
31; CHECK-NEXT: args uses:
32; CHECK-NEXT: allocas uses:
33; CHECK-NEXT: x[4]: [0,1){{$}}
34; CHECK-NOT: ]:
35entry:
36  %x = alloca i32, align 4
37  %x1 = bitcast i32* %x to i8*
38  store i8 0, i8* %x1, align 1
39  ret void
40}
41
42define void @StoreInBounds2() {
43; CHECK-LABEL: @StoreInBounds2 dso_preemptable{{$}}
44; CHECK-NEXT: args uses:
45; CHECK-NEXT: allocas uses:
46; CHECK-NEXT: x[4]: [0,4){{$}}
47; CHECK-NOT: ]:
48entry:
49  %x = alloca i32, align 4
50  store i32 0, i32* %x, align 4
51  ret void
52}
53
54define void @StoreInBounds3() {
55; CHECK-LABEL: @StoreInBounds3 dso_preemptable{{$}}
56; CHECK-NEXT: args uses:
57; CHECK-NEXT: allocas uses:
58; CHECK-NEXT: x[4]: [2,3){{$}}
59; CHECK-NOT: ]:
60entry:
61  %x = alloca i32, align 4
62  %x1 = bitcast i32* %x to i8*
63  %x2 = getelementptr i8, i8* %x1, i64 2
64  store i8 0, i8* %x2, align 1
65  ret void
66}
67
68; FIXME: ScalarEvolution does not look through ptrtoint/inttoptr.
69define void @StoreInBounds4() {
70; CHECK-LABEL: @StoreInBounds4 dso_preemptable{{$}}
71; CHECK-NEXT: args uses:
72; CHECK-NEXT: allocas uses:
73; CHECK-NEXT: x[4]: [-9223372036854775808,9223372036854775807){{$}}
74; CHECK-NOT: ]:
75entry:
76  %x = alloca i32, align 4
77  %x1 = ptrtoint i32* %x to i64
78  %x2 = add i64 %x1, 2
79  %x3 = inttoptr i64 %x2 to i8*
80  store i8 0, i8* %x3, align 1
81  ret void
82}
83
84define void @StoreOutOfBounds() {
85; CHECK-LABEL: @StoreOutOfBounds dso_preemptable{{$}}
86; CHECK-NEXT: args uses:
87; CHECK-NEXT: allocas uses:
88; CHECK-NEXT: x[4]: [2,6){{$}}
89; CHECK-NOT: ]:
90entry:
91  %x = alloca i32, align 4
92  %x1 = bitcast i32* %x to i8*
93  %x2 = getelementptr i8, i8* %x1, i64 2
94  %x3 = bitcast i8* %x2 to i32*
95  store i32 0, i32* %x3, align 1
96  ret void
97}
98
99; There is no difference in load vs store handling.
100define void @LoadInBounds() {
101; CHECK-LABEL: @LoadInBounds dso_preemptable{{$}}
102; CHECK-NEXT: args uses:
103; CHECK-NEXT: allocas uses:
104; CHECK-NEXT: x[4]: [0,1){{$}}
105; CHECK-NOT: ]:
106entry:
107  %x = alloca i32, align 4
108  %x1 = bitcast i32* %x to i8*
109  %v = load i8, i8* %x1, align 1
110  ret void
111}
112
113define void @LoadOutOfBounds() {
114; CHECK-LABEL: @LoadOutOfBounds dso_preemptable{{$}}
115; CHECK-NEXT: args uses:
116; CHECK-NEXT: allocas uses:
117; CHECK-NEXT: x[4]: [2,6){{$}}
118; CHECK-NOT: ]:
119entry:
120  %x = alloca i32, align 4
121  %x1 = bitcast i32* %x to i8*
122  %x2 = getelementptr i8, i8* %x1, i64 2
123  %x3 = bitcast i8* %x2 to i32*
124  %v = load i32, i32* %x3, align 1
125  ret void
126}
127
128; Leak through ret.
129define i8* @Ret() {
130; CHECK-LABEL: @Ret dso_preemptable{{$}}
131; CHECK-NEXT: args uses:
132; CHECK-NEXT: allocas uses:
133; CHECK-NEXT: x[4]: full-set{{$}}
134; CHECK-NOT: ]:
135entry:
136  %x = alloca i32, align 4
137  %x1 = bitcast i32* %x to i8*
138  %x2 = getelementptr i8, i8* %x1, i64 2
139  ret i8* %x2
140}
141
142declare void @Foo(i16* %p)
143
144define void @DirectCall() {
145; CHECK-LABEL: @DirectCall dso_preemptable{{$}}
146; CHECK-NEXT: args uses:
147; CHECK-NEXT: allocas uses:
148; LOCAL-NEXT: x[8]: empty-set, @Foo(arg0, [2,3)){{$}}
149; GLOBAL-NEXT: x[8]: full-set, @Foo(arg0, [2,3)){{$}}
150; CHECK-NOT: ]:
151entry:
152  %x = alloca i64, align 4
153  %x1 = bitcast i64* %x to i16*
154  %x2 = getelementptr i16, i16* %x1, i64 1
155  call void @Foo(i16* %x2);
156  ret void
157}
158
159; Indirect calls can not be analyzed (yet).
160; FIXME: %p[]: full-set looks invalid
161define void @IndirectCall(void (i8*)* %p) {
162; CHECK-LABEL: @IndirectCall dso_preemptable{{$}}
163; CHECK-NEXT: args uses:
164; CHECK-NEXT: p[]: full-set{{$}}
165; CHECK-NEXT: allocas uses:
166; CHECK-NEXT: x[4]: full-set{{$}}
167; CHECK-NOT: ]:
168entry:
169  %x = alloca i32, align 4
170  %x1 = bitcast i32* %x to i8*
171  call void %p(i8* %x1);
172  ret void
173}
174
175define void @NonConstantOffset(i1 zeroext %z) {
176; CHECK-LABEL: @NonConstantOffset dso_preemptable{{$}}
177; CHECK-NEXT: args uses:
178; CHECK-NEXT: allocas uses:
179; FIXME: SCEV can't look through selects.
180; CHECK-NEXT: x[4]: [-4,4){{$}}
181; CHECK-NOT: ]:
182entry:
183  %x = alloca i32, align 4
184  %x1 = bitcast i32* %x to i8*
185  %idx = select i1 %z, i64 1, i64 2
186  %x2 = getelementptr i8, i8* %x1, i64 %idx
187  store i8 0, i8* %x2, align 1
188  ret void
189}
190
191define void @NegativeOffset() {
192; CHECK-LABEL: @NegativeOffset dso_preemptable{{$}}
193; CHECK-NEXT: args uses:
194; CHECK-NEXT: allocas uses:
195; CHECK-NEXT: x[40]: [-1600000000000,-1599999999996){{$}}
196; CHECK-NOT: ]:
197entry:
198  %x = alloca i32, i32 10, align 4
199  %x2 = getelementptr i32, i32* %x, i64 -400000000000
200  store i32 0, i32* %x2, align 1
201  ret void
202}
203
204define void @PossiblyNegativeOffset(i16 %z) {
205; CHECK-LABEL: @PossiblyNegativeOffset dso_preemptable{{$}}
206; CHECK-NEXT: args uses:
207; CHECK-NEXT: allocas uses:
208; CHECK-NEXT: x[40]: [-131072,131072){{$}}
209; CHECK-NOT: ]:
210entry:
211  %x = alloca i32, i32 10, align 4
212  %x2 = getelementptr i32, i32* %x, i16 %z
213  store i32 0, i32* %x2, align 1
214  ret void
215}
216
217define void @NonConstantOffsetOOB(i1 zeroext %z) {
218; CHECK-LABEL: @NonConstantOffsetOOB dso_preemptable{{$}}
219; CHECK-NEXT: args uses:
220; CHECK-NEXT: allocas uses:
221; CHECK-NEXT: x[4]: [-8,8){{$}}
222; CHECK-NOT: ]:
223entry:
224  %x = alloca i32, align 4
225  %x1 = bitcast i32* %x to i8*
226  %idx = select i1 %z, i64 1, i64 4
227  %x2 = getelementptr i8, i8* %x1, i64 %idx
228  store i8 0, i8* %x2, align 1
229  ret void
230}
231
232define void @ArrayAlloca() {
233; CHECK-LABEL: @ArrayAlloca dso_preemptable{{$}}
234; CHECK-NEXT: args uses:
235; CHECK-NEXT: allocas uses:
236; CHECK-NEXT: x[40]: [36,40){{$}}
237; CHECK-NOT: ]:
238entry:
239  %x = alloca i32, i32 10, align 4
240  %x1 = bitcast i32* %x to i8*
241  %x2 = getelementptr i8, i8* %x1, i64 36
242  %x3 = bitcast i8* %x2 to i32*
243  store i32 0, i32* %x3, align 1
244  ret void
245}
246
247define void @ArrayAllocaOOB() {
248; CHECK-LABEL: @ArrayAllocaOOB dso_preemptable{{$}}
249; CHECK-NEXT: args uses:
250; CHECK-NEXT: allocas uses:
251; CHECK-NEXT: x[40]: [37,41){{$}}
252; CHECK-NOT: ]:
253entry:
254  %x = alloca i32, i32 10, align 4
255  %x1 = bitcast i32* %x to i8*
256  %x2 = getelementptr i8, i8* %x1, i64 37
257  %x3 = bitcast i8* %x2 to i32*
258  store i32 0, i32* %x3, align 1
259  ret void
260}
261
262define void @DynamicAllocaUnused(i64 %size) {
263; CHECK-LABEL: @DynamicAllocaUnused dso_preemptable{{$}}
264; CHECK-NEXT: args uses:
265; CHECK-NEXT: allocas uses:
266; CHECK-NEXT: x[0]: empty-set{{$}}
267; CHECK-NOT: ]:
268entry:
269  %x = alloca i32, i64 %size, align 16
270  ret void
271}
272
273; Dynamic alloca with unknown size.
274define void @DynamicAlloca(i64 %size) {
275; CHECK-LABEL: @DynamicAlloca dso_preemptable{{$}}
276; CHECK-NEXT: args uses:
277; CHECK-NEXT: allocas uses:
278; CHECK-NEXT: x[0]: [0,4){{$}}
279; CHECK-NOT: ]:
280entry:
281  %x = alloca i32, i64 %size, align 16
282  store i32 0, i32* %x, align 1
283  ret void
284}
285
286; Dynamic alloca with limited size.
287; FIXME: could be proved safe. Implement.
288define void @DynamicAllocaFiniteSizeRange(i1 zeroext %z) {
289; CHECK-LABEL: @DynamicAllocaFiniteSizeRange dso_preemptable{{$}}
290; CHECK-NEXT: args uses:
291; CHECK-NEXT: allocas uses:
292; CHECK-NEXT: x[0]: [0,4){{$}}
293; CHECK-NOT: ]:
294entry:
295  %size = select i1 %z, i64 3, i64 5
296  %x = alloca i32, i64 %size, align 16
297  store i32 0, i32* %x, align 1
298  ret void
299}
300
301define signext i8 @SimpleLoop() {
302; CHECK-LABEL: @SimpleLoop dso_preemptable{{$}}
303; CHECK-NEXT: args uses:
304; CHECK-NEXT: allocas uses:
305; CHECK-NEXT: x[10]: [0,10){{$}}
306; CHECK-NOT: ]:
307entry:
308  %x = alloca [10 x i8], align 1
309  %0 = getelementptr inbounds [10 x i8], [10 x i8]* %x, i64 0, i64 0
310  %lftr.limit = getelementptr inbounds [10 x i8], [10 x i8]* %x, i64 0, i64 10
311  br label %for.body
312
313for.body:
314  %sum.010 = phi i8 [ 0, %entry ], [ %add, %for.body ]
315  %p.09 = phi i8* [ %0, %entry ], [ %incdec.ptr, %for.body ]
316  %incdec.ptr = getelementptr inbounds i8, i8* %p.09, i64 1
317  %1 = load volatile i8, i8* %p.09, align 1
318  %add = add i8 %1, %sum.010
319  %exitcond = icmp eq i8* %incdec.ptr, %lftr.limit
320  br i1 %exitcond, label %for.cond.cleanup, label %for.body
321
322for.cond.cleanup:
323  ret i8 %add
324}
325
326; OOB in a loop.
327define signext i8 @SimpleLoopOOB() {
328; CHECK-LABEL: @SimpleLoopOOB dso_preemptable{{$}}
329; CHECK-NEXT: args uses:
330; CHECK-NEXT: allocas uses:
331; CHECK-NEXT: x[10]: [0,11){{$}}
332; CHECK-NOT: ]:
333entry:
334  %x = alloca [10 x i8], align 1
335  %0 = getelementptr inbounds [10 x i8], [10 x i8]* %x, i64 0, i64 0
336 ; 11 iterations
337  %lftr.limit = getelementptr inbounds [10 x i8], [10 x i8]* %x, i64 0, i64 11
338  br label %for.body
339
340for.body:
341  %sum.010 = phi i8 [ 0, %entry ], [ %add, %for.body ]
342  %p.09 = phi i8* [ %0, %entry ], [ %incdec.ptr, %for.body ]
343  %incdec.ptr = getelementptr inbounds i8, i8* %p.09, i64 1
344  %1 = load volatile i8, i8* %p.09, align 1
345  %add = add i8 %1, %sum.010
346  %exitcond = icmp eq i8* %incdec.ptr, %lftr.limit
347  br i1 %exitcond, label %for.cond.cleanup, label %for.body
348
349for.cond.cleanup:
350  ret i8 %add
351}
352
353define dso_local void @SizeCheck(i32 %sz) {
354; CHECK-LABEL: @SizeCheck{{$}}
355; CHECK-NEXT: args uses:
356; CHECK-NEXT: allocas uses:
357; CHECK-NEXT: x1[128]: [0,4294967295){{$}}
358; CHECK-NOT: ]:
359entry:
360  %x1 = alloca [128 x i8], align 16
361  %x1.sub = getelementptr inbounds [128 x i8], [128 x i8]* %x1, i64 0, i64 0
362  %cmp = icmp slt i32 %sz, 129
363  br i1 %cmp, label %if.then, label %if.end
364
365if.then:
366  call void @llvm.memset.p0i8.i32(i8* nonnull align 16 %x1.sub, i8 0, i32 %sz, i1 false)
367  br label %if.end
368
369if.end:
370  ret void
371}
372
373; FIXME: scalable allocas are considered to be of size zero, and scalable accesses to be full-range.
374; This effectively disables safety analysis for scalable allocations.
375define void @Scalable(<vscale x 4 x i32>* %p, <vscale x 4 x i32>* %unused, <vscale x 4 x i32> %v) {
376; CHECK-LABEL: @Scalable dso_preemptable{{$}}
377; CHECK-NEXT: args uses:
378; CHECK-NEXT:   p[]: full-set
379; CHECK-NEXT:   unused[]: empty-set
380; CHECK-NEXT: allocas uses:
381; CHECK-NEXT:   x[0]: [0,1){{$}}
382; CHECK-NOT: ]:
383entry:
384  %x = alloca <vscale x 4 x i32>, align 4
385  %x1 = bitcast <vscale x 4 x i32>* %x to i8*
386  store i8 0, i8* %x1, align 1
387  store <vscale x 4 x i32> %v, <vscale x 4 x i32>* %p, align 4
388  ret void
389}
390
391%zerosize_type = type {}
392
393define void @ZeroSize(%zerosize_type *%p)  {
394; CHECK-LABEL: @ZeroSize dso_preemptable{{$}}
395; CHECK-NEXT: args uses:
396; CHECK-NEXT:   p[]: empty-set
397; CHECK-NEXT: allocas uses:
398; CHECK-NEXT:   x[0]: empty-set
399; CHECK-NOT: ]:
400entry:
401  %x = alloca %zerosize_type, align 4
402  store %zerosize_type undef, %zerosize_type* %x, align 4
403  store %zerosize_type undef, %zerosize_type* undef, align 4
404  %val = load %zerosize_type, %zerosize_type* %p, align 4
405  ret void
406}
407
408define void @OperandBundle() {
409; CHECK-LABEL: @OperandBundle dso_preemptable{{$}}
410; CHECK-NEXT: args uses:
411; CHECK-NEXT: allocas uses:
412; CHECK-NEXT:   a[4]: full-set
413; CHECK-NOT: ]:
414entry:
415  %a = alloca i32, align 4
416  call void @LeakAddress() ["unknown"(i32* %a)]
417  ret void
418}
419
420define void @ByVal(i16* byval %p) {
421  ; CHECK-LABEL: @ByVal dso_preemptable{{$}}
422  ; CHECK-NEXT: args uses:
423  ; CHECK-NEXT: allocas uses:
424  ; CHECK-NOT: ]:
425entry:
426  ret void
427}
428
429define void @TestByVal() {
430; CHECK-LABEL: @TestByVal dso_preemptable{{$}}
431; CHECK-NEXT: args uses:
432; CHECK-NEXT: allocas uses:
433; CHECK-NEXT: x[2]: [0,2)
434; CHECK-NEXT: y[8]: [0,2)
435; CHECK-NOT: ]:
436entry:
437  %x = alloca i16, align 4
438  call void @ByVal(i16* byval %x)
439
440  %y = alloca i64, align 4
441  %y1 = bitcast i64* %y to i16*
442  call void @ByVal(i16* byval %y1)
443
444  ret void
445}
446
447declare void @ByValArray([100000 x i64]* byval %p)
448
449define void @TestByValArray() {
450; CHECK-LABEL: @TestByValArray dso_preemptable{{$}}
451; CHECK-NEXT: args uses:
452; CHECK-NEXT: allocas uses:
453; CHECK-NEXT: z[800000]: [500000,1300000)
454; CHECK-NOT: ]:
455entry:
456  %z = alloca [100000 x i64], align 4
457  %z1 = bitcast [100000 x i64]* %z to i8*
458  %z2 = getelementptr i8, i8* %z1, i64 500000
459  %z3 = bitcast i8* %z2 to [100000 x i64]*
460  call void @ByValArray([100000 x i64]* byval %z3)
461  ret void
462}
463
464define dso_local i8 @LoadMinInt64(i8* %p) {
465  ; CHECK-LABEL: @LoadMinInt64{{$}}
466  ; CHECK-NEXT: args uses:
467  ; CHECK-NEXT: p[]: [-9223372036854775808,-9223372036854775807){{$}}
468  ; CHECK-NEXT: allocas uses:
469  ; CHECK-NOT: ]:
470  %p2 = getelementptr i8, i8* %p, i64 -9223372036854775808
471  %v = load i8, i8* %p2, align 1
472  ret i8 %v
473}
474
475define void @Overflow() {
476; CHECK-LABEL: @Overflow dso_preemptable{{$}}
477; CHECK-NEXT: args uses:
478; CHECK-NEXT: allocas uses:
479; LOCAL-NEXT: x[1]: empty-set, @LoadMinInt64(arg0, [-9223372036854775808,-9223372036854775807)){{$}}
480; GLOBAL-NEXT: x[1]: full-set, @LoadMinInt64(arg0, [-9223372036854775808,-9223372036854775807)){{$}}
481; CHECK-NOT: ]:
482entry:
483  %x = alloca i8, align 4
484  %x2 = getelementptr i8, i8* %x, i64 -9223372036854775808
485  %v = call i8 @LoadMinInt64(i8* %x2)
486  ret void
487}
488
489define void @DeadBlock(i64* %p) {
490; CHECK-LABEL: @DeadBlock dso_preemptable{{$}}
491; CHECK-NEXT: args uses:
492; CHECK-NEXT: p[]: empty-set{{$}}
493; CHECK-NEXT: allocas uses:
494; CHECK-NEXT: x[1]: empty-set{{$}}
495; CHECK-NOT: ]:
496entry:
497  %x = alloca i8, align 4
498  br label %end
499
500dead:
501  store i8 5, i8* %x
502  store i64 -5, i64* %p
503  br label %end
504
505end:
506  ret void
507}
508
509define void @LifeNotStarted() {
510; CHECK-LABEL: @LifeNotStarted dso_preemptable{{$}}
511; CHECK-NEXT: args uses:
512; CHECK-NEXT: allocas uses:
513; CHECK: x[1]: full-set{{$}}
514; CHECK: y[1]: full-set{{$}}
515; CHECK: z[1]: full-set{{$}}
516; CHECK-NOT: ]:
517entry:
518  %x = alloca i8, align 4
519  %y = alloca i8, align 4
520  %z = alloca i8, align 4
521
522  store i8 5, i8* %x
523  %n = load i8, i8* %y
524  call void @llvm.memset.p0i8.i32(i8* nonnull %z, i8 0, i32 1, i1 false)
525
526  call void @llvm.lifetime.start.p0i8(i64 1, i8* %x)
527  call void @llvm.lifetime.start.p0i8(i64 1, i8* %y)
528  call void @llvm.lifetime.start.p0i8(i64 1, i8* %z)
529
530  ret void
531}
532
533define void @LifeOK() {
534; CHECK-LABEL: @LifeOK dso_preemptable{{$}}
535; CHECK-NEXT: args uses:
536; CHECK-NEXT: allocas uses:
537; CHECK: x[1]: [0,1){{$}}
538; CHECK: y[1]: [0,1){{$}}
539; CHECK: z[1]: [0,1){{$}}
540; CHECK-NOT: ]:
541entry:
542  %x = alloca i8, align 4
543  %y = alloca i8, align 4
544  %z = alloca i8, align 4
545
546  call void @llvm.lifetime.start.p0i8(i64 1, i8* %x)
547  call void @llvm.lifetime.start.p0i8(i64 1, i8* %y)
548  call void @llvm.lifetime.start.p0i8(i64 1, i8* %z)
549
550  store i8 5, i8* %x
551  %n = load i8, i8* %y
552  call void @llvm.memset.p0i8.i32(i8* nonnull %z, i8 0, i32 1, i1 false)
553
554  ret void
555}
556
557define void @LifeEnded() {
558; CHECK-LABEL: @LifeEnded dso_preemptable{{$}}
559; CHECK-NEXT: args uses:
560; CHECK-NEXT: allocas uses:
561; CHECK: x[1]: full-set{{$}}
562; CHECK: y[1]: full-set{{$}}
563; CHECK: z[1]: full-set{{$}}
564; CHECK-NOT: ]:
565entry:
566  %x = alloca i8, align 4
567  %y = alloca i8, align 4
568  %z = alloca i8, align 4
569
570  call void @llvm.lifetime.start.p0i8(i64 1, i8* %x)
571  call void @llvm.lifetime.start.p0i8(i64 1, i8* %y)
572  call void @llvm.lifetime.start.p0i8(i64 1, i8* %z)
573
574  call void @llvm.lifetime.end.p0i8(i64 1, i8* %x)
575  call void @llvm.lifetime.end.p0i8(i64 1, i8* %y)
576  call void @llvm.lifetime.end.p0i8(i64 1, i8* %z)
577
578  store i8 5, i8* %x
579  %n = load i8, i8* %y
580  call void @llvm.memset.p0i8.i32(i8* nonnull %z, i8 0, i32 1, i1 false)
581
582  ret void
583}
584
585declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture)
586declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture)