[AMDGPU] Add True16 register classes.
[llvm-project.git] / llvm / test / Analysis / StackSafetyAnalysis / local.ll
blob6314be0cf85a05a82f94d22ad4f1d95e3a292810
1 ; RUN: opt -S -passes="print<stack-safety-local>" -disable-output < %s 2>&1 | FileCheck %s --check-prefixes=CHECK,LOCAL
2 ; RUN: opt -S -passes="print-stack-safety" -disable-output < %s 2>&1 | FileCheck %s --check-prefixes=CHECK,GLOBAL
4 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
5 target triple = "x86_64-unknown-linux-gnu"
7 @sink = global ptr null, align 8
9 declare void @llvm.memset.p0.i32(ptr %dest, i8 %val, i32 %len, i1 %isvolatile)
10 declare void @llvm.memcpy.p0.p0.i32(ptr %dest, ptr %src, i32 %len, i1 %isvolatile)
11 declare void @llvm.memmove.p0.p0.i32(ptr %dest, ptr %src, i32 %len, i1 %isvolatile)
12 declare void @llvm.memset.p0.i64(ptr %dest, i8 %val, i64 %len, i1 %isvolatile)
14 declare void @unknown_call(ptr %dest)
15 declare ptr @retptr(ptr returned)
17 ; Address leaked.
18 define void @LeakAddress() {
19 ; CHECK-LABEL: @LeakAddress dso_preemptable{{$}}
20 ; CHECK-NEXT: args uses:
21 ; CHECK-NEXT: allocas uses:
22 ; CHECK-NEXT: x[4]: full-set{{$}}
23 ; GLOBAL-NEXT: safe accesses:
24 ; CHECK-EMPTY:
25 entry:
26   %x = alloca i32, align 4
27   store ptr %x, ptr @sink, align 8
28   ret void
31 define void @StoreInBounds() {
32 ; CHECK-LABEL: @StoreInBounds dso_preemptable{{$}}
33 ; CHECK-NEXT: args uses:
34 ; CHECK-NEXT: allocas uses:
35 ; CHECK-NEXT: x[4]: [0,1){{$}}
36 ; GLOBAL-NEXT: safe accesses:
37 ; GLOBAL-NEXT: store i8 0, ptr %x, align 1
38 ; CHECK-EMPTY:
39 entry:
40   %x = alloca i32, align 4
41   store i8 0, ptr %x, align 1
42   ret void
45 define void @StoreInBoundsCond(i64 %i) {
46 ; CHECK-LABEL: @StoreInBoundsCond dso_preemptable{{$}}
47 ; CHECK-NEXT: args uses:
48 ; CHECK-NEXT: allocas uses:
49 ; CHECK-NEXT: x[4]: full-set{{$}}
50 ; GLOBAL-NEXT: safe accesses:
51 ; GLOBAL-NEXT: store i8 0, ptr %x2, align 1
52 ; CHECK-EMPTY:
53 entry:
54   %x = alloca i32, align 4
55   %c1 = icmp sge i64 %i, 0
56   %c2 = icmp slt i64 %i, 4
57   br i1 %c1, label %c1.true, label %false
59 c1.true:
60   br i1 %c2, label %c2.true, label %false
62 c2.true:
63   %x2 = getelementptr i8, ptr %x, i64 %i
64   store i8 0, ptr %x2, align 1
65   br label %false
67 false:
68   ret void
71 define void @StoreInBoundsMinMax(i64 %i) {
72 ; CHECK-LABEL: @StoreInBoundsMinMax dso_preemptable{{$}}
73 ; CHECK-NEXT: args uses:
74 ; CHECK-NEXT: allocas uses:
75 ; CHECK-NEXT: x[4]: [0,4){{$}}
76 ; GLOBAL-NEXT: safe accesses:
77 ; GLOBAL-NEXT: store i8 0, ptr %x2, align 1
78 ; CHECK-EMPTY:
79 entry:
80   %x = alloca i32, align 4
81   %c1 = icmp sge i64 %i, 0
82   %i1 = select i1 %c1, i64 %i, i64 0
83   %c2 = icmp slt i64 %i1, 3
84   %i2 = select i1 %c2, i64 %i1, i64 3
85   %x2 = getelementptr i8, ptr %x, i64 %i2
86   store i8 0, ptr %x2, align 1
87   ret void
90 define void @StoreInBounds2() {
91 ; CHECK-LABEL: @StoreInBounds2 dso_preemptable{{$}}
92 ; CHECK-NEXT: args uses:
93 ; CHECK-NEXT: allocas uses:
94 ; CHECK-NEXT: x[4]: [0,4){{$}}
95 ; GLOBAL-NEXT: safe accesses:
96 ; GLOBAL-NEXT: store i32 0, ptr %x, align 4
97 ; CHECK-EMPTY:
98 entry:
99   %x = alloca i32, align 4
100   store i32 0, ptr %x, align 4
101   ret void
104 define void @StoreInBounds3() {
105 ; CHECK-LABEL: @StoreInBounds3 dso_preemptable{{$}}
106 ; CHECK-NEXT: args uses:
107 ; CHECK-NEXT: allocas uses:
108 ; CHECK-NEXT: x[4]: [2,3){{$}}
109 ; GLOBAL-NEXT: safe accesses:
110 ; GLOBAL-NEXT: store i8 0, ptr %x2, align 1
111 ; CHECK-EMPTY:
112 entry:
113   %x = alloca i32, align 4
114   %x2 = getelementptr i8, ptr %x, i64 2
115   store i8 0, ptr %x2, align 1
116   ret void
119 ; FIXME: ScalarEvolution does not look through ptrtoint/inttoptr.
120 define void @StoreInBounds4() {
121 ; CHECK-LABEL: @StoreInBounds4 dso_preemptable{{$}}
122 ; CHECK-NEXT: args uses:
123 ; CHECK-NEXT: allocas uses:
124 ; CHECK-NEXT: x[4]: full-set{{$}}
125 ; GLOBAL-NEXT: safe accesses:
126 ; CHECK-EMPTY:
127 entry:
128   %x = alloca i32, align 4
129   %x1 = ptrtoint ptr %x to i64
130   %x2 = add i64 %x1, 2
131   %x3 = inttoptr i64 %x2 to ptr
132   store i8 0, ptr %x3, align 1
133   ret void
136 define void @StoreInBounds6() {
137 ; CHECK-LABEL: @StoreInBounds6 dso_preemptable{{$}}
138 ; CHECK-NEXT: args uses:
139 ; CHECK-NEXT: allocas uses:
140 ; GLOBAL-NEXT: x[4]: full-set, @retptr(arg0, [0,1)){{$}}
141 ; LOCAL-NEXT: x[4]: [0,1), @retptr(arg0, [0,1)){{$}}
142 ; GLOBAL-NEXT: safe accesses:
143 ; GLOBAL-NEXT: store i8 0, ptr %x2, align 1
144 ; CHECK-EMPTY:
145 entry:
146   %x = alloca i32, align 4
147   %x2 = call ptr @retptr(ptr %x)
148   store i8 0, ptr %x2, align 1
149   ret void
152 define dso_local void @WriteMinMax(ptr %p) {
153 ; CHECK-LABEL: @WriteMinMax{{$}}
154 ; CHECK-NEXT: args uses:
155 ; CHECK-NEXT: p[]: full-set
156 ; CHECK-NEXT: allocas uses:
157 ; GLOBAL-NEXT: safe accesses:
158 ; GLOBAL-NEXT: store i8 0, ptr %p1, align 1
159 ; GLOBAL-NEXT: store i8 0, ptr %p2, align 1
160 ; CHECK-EMPTY:
161 entry:
162   %p1 = getelementptr i8, ptr %p, i64 9223372036854775805
163   store i8 0, ptr %p1, align 1
164   %p2 = getelementptr i8, ptr %p, i64 -9223372036854775805
165   store i8 0, ptr %p2, align 1
166   ret void
169 define dso_local void @WriteMax(ptr %p) {
170 ; CHECK-LABEL: @WriteMax{{$}}
171 ; CHECK-NEXT: args uses:
172 ; CHECK-NEXT: p[]: [-9223372036854775807,9223372036854775806)
173 ; CHECK-NEXT: allocas uses:
174 ; GLOBAL-NEXT: safe accesses:
175 ; GLOBAL-NEXT: call void @llvm.memset.p0.i64(ptr %p, i8 1, i64 9223372036854775806, i1 false)
176 ; GLOBAL-NEXT: call void @llvm.memset.p0.i64(ptr %p2, i8 1, i64 9223372036854775806, i1 false)
177 ; CHECK-EMPTY:
178 entry:
179   call void @llvm.memset.p0.i64(ptr %p, i8 1, i64 9223372036854775806, i1 0)
180   %p2 = getelementptr i8, ptr %p, i64 -9223372036854775807
181   call void @llvm.memset.p0.i64(ptr %p2, i8 1, i64 9223372036854775806, i1 0)
182   ret void
185 define void @StoreOutOfBounds() {
186 ; CHECK-LABEL: @StoreOutOfBounds dso_preemptable{{$}}
187 ; CHECK-NEXT: args uses:
188 ; CHECK-NEXT: allocas uses:
189 ; CHECK-NEXT: x[4]: [2,6){{$}}
190 ; GLOBAL-NEXT: safe accesses:
191 ; CHECK-EMPTY:
192 entry:
193   %x = alloca i32, align 4
194   %x2 = getelementptr i8, ptr %x, i64 2
195   store i32 0, ptr %x2, align 1
196   ret void
199 define void @StoreOutOfBoundsCond(i64 %i) {
200 ; CHECK-LABEL: @StoreOutOfBoundsCond dso_preemptable{{$}}
201 ; CHECK-NEXT: args uses:
202 ; CHECK-NEXT: allocas uses:
203 ; CHECK-NEXT: x[4]: full-set{{$}}
204 ; GLOBAL-NEXT: safe accesses:
205 ; CHECK-EMPTY:
206 entry:
207   %x = alloca i32, align 4
208   %c1 = icmp sge i64 %i, 0
209   %c2 = icmp slt i64 %i, 5
210   br i1 %c1, label %c1.true, label %false
212 c1.true:
213   br i1 %c2, label %c2.true, label %false
215 c2.true:
216   %x2 = getelementptr i8, ptr %x, i64 %i
217   store i8 0, ptr %x2, align 1
218   br label %false
220 false:
221   ret void
224 define void @StoreOutOfBoundsCond2(i64 %i) {
225 ; CHECK-LABEL: @StoreOutOfBoundsCond2 dso_preemptable{{$}}
226 ; CHECK-NEXT: args uses:
227 ; CHECK-NEXT: allocas uses:
228 ; CHECK-NEXT: x[4]: full-set{{$}}
229 ; GLOBAL-NEXT: safe accesses:
230 ; CHECK-EMPTY:
231 entry:
232   %x = alloca i32, align 4
233   %c2 = icmp slt i64 %i, 5
234   br i1 %c2, label %c2.true, label %false
236 c2.true:
237   %x2 = getelementptr i8, ptr %x, i64 %i
238   store i8 0, ptr %x2, align 1
239   br label %false
241 false:
242   ret void
245 define void @StoreOutOfBounds2() {
246 ; CHECK-LABEL: @StoreOutOfBounds2 dso_preemptable{{$}}
247 ; CHECK-NEXT: args uses:
248 ; CHECK-NEXT: allocas uses:
249 ; GLOBAL-NEXT: x[4]: full-set, @retptr(arg0, [2,3)){{$}}
250 ; LOCAL-NEXT: x[4]: [2,6), @retptr(arg0, [2,3)){{$}}
251 ; GLOBAL-NEXT: safe accesses:
252 ; CHECK-EMPTY:
253 entry:
254   %x = alloca i32, align 4
255   %x2 = getelementptr i8, ptr %x, i64 2
256   %x3 = call ptr @retptr(ptr %x2)
257   store i32 0, ptr %x3, align 1
258   ret void
261 ; There is no difference in load vs store handling.
262 define void @LoadInBounds() {
263 ; CHECK-LABEL: @LoadInBounds dso_preemptable{{$}}
264 ; CHECK-NEXT: args uses:
265 ; CHECK-NEXT: allocas uses:
266 ; CHECK-NEXT: x[4]: [0,1){{$}}
267 ; GLOBAL-NEXT: safe accesses:
268 ; GLOBAL-NEXT: %v = load i8, ptr %x, align 1
269 ; CHECK-EMPTY:
270 entry:
271   %x = alloca i32, align 4
272   %v = load i8, ptr %x, align 1
273   ret void
276 define void @LoadOutOfBounds() {
277 ; CHECK-LABEL: @LoadOutOfBounds dso_preemptable{{$}}
278 ; CHECK-NEXT: args uses:
279 ; CHECK-NEXT: allocas uses:
280 ; CHECK-NEXT: x[4]: [2,6){{$}}
281 ; GLOBAL-NEXT: safe accesses:
282 ; CHECK-EMPTY:
283 entry:
284   %x = alloca i32, align 4
285   %x2 = getelementptr i8, ptr %x, i64 2
286   %v = load i32, ptr %x2, align 1
287   ret void
290 ; Leak through ret.
291 define ptr @Ret() {
292 ; CHECK-LABEL: @Ret dso_preemptable{{$}}
293 ; CHECK-NEXT: args uses:
294 ; CHECK-NEXT: allocas uses:
295 ; CHECK-NEXT: x[4]: full-set{{$}}
296 ; GLOBAL-NEXT: safe accesses:
297 ; CHECK-EMPTY:
298 entry:
299   %x = alloca i32, align 4
300   %x2 = getelementptr i8, ptr %x, i64 2
301   ret ptr %x2
304 declare void @Foo(ptr %p)
306 define void @DirectCall() {
307 ; CHECK-LABEL: @DirectCall dso_preemptable{{$}}
308 ; CHECK-NEXT: args uses:
309 ; CHECK-NEXT: allocas uses:
310 ; LOCAL-NEXT: x[8]: empty-set, @Foo(arg0, [2,3)){{$}}
311 ; GLOBAL-NEXT: x[8]: full-set, @Foo(arg0, [2,3)){{$}}
312 ; GLOBAL-NEXT: safe accesses:
313 ; CHECK-EMPTY:
314 entry:
315   %x = alloca i64, align 4
316   %x2 = getelementptr i16, ptr %x, i64 1
317   call void @Foo(ptr %x2);
318   ret void
321 ; Indirect calls can not be analyzed (yet).
322 ; FIXME: %p[]: full-set looks invalid
323 define void @IndirectCall(ptr %p) {
324 ; CHECK-LABEL: @IndirectCall dso_preemptable{{$}}
325 ; CHECK-NEXT: args uses:
326 ; CHECK-NEXT: p[]: full-set{{$}}
327 ; CHECK-NEXT: allocas uses:
328 ; CHECK-NEXT: x[4]: full-set{{$}}
329 ; GLOBAL-NEXT: safe accesses:
330 ; CHECK-EMPTY:
331 entry:
332   %x = alloca i32, align 4
333   call void %p(ptr %x);
334   ret void
337 define void @NonConstantOffset(i1 zeroext %z) {
338 ; CHECK-LABEL: @NonConstantOffset dso_preemptable{{$}}
339 ; CHECK-NEXT: args uses:
340 ; CHECK-NEXT: allocas uses:
341 ; FIXME: SCEV can't look through selects.
342 ; CHECK-NEXT: x[4]: [0,4){{$}}
343 ; GLOBAL-NEXT: safe accesses:
344 ; GLOBAL-NEXT: store i8 0, ptr %x2, align 1
345 ; CHECK-EMPTY:
346 entry:
347   %x = alloca i32, align 4
348   %idx = select i1 %z, i64 1, i64 2
349   %x2 = getelementptr i8, ptr %x, i64 %idx
350   store i8 0, ptr %x2, align 1
351   ret void
354 define void @NegativeOffset() {
355 ; CHECK-LABEL: @NegativeOffset dso_preemptable{{$}}
356 ; CHECK-NEXT: args uses:
357 ; CHECK-NEXT: allocas uses:
358 ; CHECK-NEXT: x[40]: [-1600000000000,-1599999999996){{$}}
359 ; GLOBAL-NEXT: safe accesses:
360 ; CHECK-EMPTY:
361 entry:
362   %x = alloca i32, i32 10, align 4
363   %x2 = getelementptr i32, ptr %x, i64 -400000000000
364   store i32 0, ptr %x2, align 1
365   ret void
368 define void @PossiblyNegativeOffset(i16 %z) {
369 ; CHECK-LABEL: @PossiblyNegativeOffset dso_preemptable{{$}}
370 ; CHECK-NEXT: args uses:
371 ; CHECK-NEXT: allocas uses:
372 ; CHECK-NEXT: x[40]: [-131072,131072){{$}}
373 ; GLOBAL-NEXT: safe accesses:
374 ; CHECK-EMPTY:
375 entry:
376   %x = alloca i32, i32 10, align 4
377   %x2 = getelementptr i32, ptr %x, i16 %z
378   store i32 0, ptr %x2, align 1
379   ret void
382 define void @NonConstantOffsetOOB(i1 zeroext %z) {
383 ; CHECK-LABEL: @NonConstantOffsetOOB dso_preemptable{{$}}
384 ; CHECK-NEXT: args uses:
385 ; CHECK-NEXT: allocas uses:
386 ; CHECK-NEXT: x[4]: [0,6){{$}}
387 ; GLOBAL-NEXT: safe accesses:
388 ; CHECK-EMPTY:
389 entry:
390   %x = alloca i32, align 4
391   %idx = select i1 %z, i64 1, i64 4
392   %x2 = getelementptr i8, ptr %x, i64 %idx
393   store i8 0, ptr %x2, align 1
394   ret void
397 define void @ArrayAlloca() {
398 ; CHECK-LABEL: @ArrayAlloca dso_preemptable{{$}}
399 ; CHECK-NEXT: args uses:
400 ; CHECK-NEXT: allocas uses:
401 ; CHECK-NEXT: x[40]: [36,40){{$}}
402 ; GLOBAL-NEXT: safe accesses:
403 ; GLOBAL-NEXT: store i32 0, ptr %x2, align 1
404 ; CHECK-EMPTY:
405 entry:
406   %x = alloca i32, i32 10, align 4
407   %x2 = getelementptr i8, ptr %x, i64 36
408   store i32 0, ptr %x2, align 1
409   ret void
412 define void @ArrayAllocaOOB() {
413 ; CHECK-LABEL: @ArrayAllocaOOB dso_preemptable{{$}}
414 ; CHECK-NEXT: args uses:
415 ; CHECK-NEXT: allocas uses:
416 ; CHECK-NEXT: x[40]: [37,41){{$}}
417 ; GLOBAL-NEXT: safe accesses:
418 ; CHECK-EMPTY:
419 entry:
420   %x = alloca i32, i32 10, align 4
421   %x2 = getelementptr i8, ptr %x, i64 37
422   store i32 0, ptr %x2, align 1
423   ret void
426 define void @DynamicAllocaUnused(i64 %size) {
427 ; CHECK-LABEL: @DynamicAllocaUnused dso_preemptable{{$}}
428 ; CHECK-NEXT: args uses:
429 ; CHECK-NEXT: allocas uses:
430 ; CHECK-NEXT: x[0]: empty-set{{$}}
431 ; GLOBAL-NEXT: safe accesses:
432 ; CHECK-EMPTY:
433 entry:
434   %x = alloca i32, i64 %size, align 16
435   ret void
438 ; Dynamic alloca with unknown size.
439 define void @DynamicAlloca(i64 %size) {
440 ; CHECK-LABEL: @DynamicAlloca dso_preemptable{{$}}
441 ; CHECK-NEXT: args uses:
442 ; CHECK-NEXT: allocas uses:
443 ; CHECK-NEXT: x[0]: [0,4){{$}}
444 ; GLOBAL-NEXT: safe accesses:
445 ; CHECK-EMPTY:
446 entry:
447   %x = alloca i32, i64 %size, align 16
448   store i32 0, ptr %x, align 1
449   ret void
452 ; Dynamic alloca with limited size.
453 ; FIXME: could be proved safe. Implement.
454 define void @DynamicAllocaFiniteSizeRange(i1 zeroext %z) {
455 ; CHECK-LABEL: @DynamicAllocaFiniteSizeRange dso_preemptable{{$}}
456 ; CHECK-NEXT: args uses:
457 ; CHECK-NEXT: allocas uses:
458 ; CHECK-NEXT: x[0]: [0,4){{$}}
459 ; GLOBAL-NEXT: safe accesses:
460 ; CHECK-EMPTY:
461 entry:
462   %size = select i1 %z, i64 3, i64 5
463   %x = alloca i32, i64 %size, align 16
464   store i32 0, ptr %x, align 1
465   ret void
468 define signext i8 @SimpleLoop() {
469 ; CHECK-LABEL: @SimpleLoop dso_preemptable{{$}}
470 ; CHECK-NEXT: args uses:
471 ; CHECK-NEXT: allocas uses:
472 ; CHECK-NEXT: x[10]: [0,10){{$}}
473 ; GLOBAL-NEXT: safe accesses:
474 ; GLOBAL-NEXT: %load = load volatile i8, ptr %p.09, align 1
475 ; CHECK-EMPTY:
476 entry:
477   %x = alloca [10 x i8], align 1
478   %lftr.limit = getelementptr inbounds [10 x i8], ptr %x, i64 0, i64 10
479   br label %for.body
481 for.body:
482   %sum.010 = phi i8 [ 0, %entry ], [ %add, %for.body ]
483   %p.09 = phi ptr [ %x, %entry ], [ %incdec.ptr, %for.body ]
484   %incdec.ptr = getelementptr inbounds i8, ptr %p.09, i64 1
485   %load = load volatile i8, ptr %p.09, align 1
486   %add = add i8 %load, %sum.010
487   %exitcond = icmp eq ptr %incdec.ptr, %lftr.limit
488   br i1 %exitcond, label %for.cond.cleanup, label %for.body
490 for.cond.cleanup:
491   ret i8 %add
494 ; OOB in a loop.
495 define signext i8 @SimpleLoopOOB() {
496 ; CHECK-LABEL: @SimpleLoopOOB dso_preemptable{{$}}
497 ; CHECK-NEXT: args uses:
498 ; CHECK-NEXT: allocas uses:
499 ; CHECK-NEXT: x[10]: [0,11){{$}}
500 ; GLOBAL-NEXT: safe accesses:
501 ; CHECK-EMPTY:
502 entry:
503   %x = alloca [10 x i8], align 1
504  ; 11 iterations
505   %lftr.limit = getelementptr inbounds [10 x i8], ptr %x, i64 0, i64 11
506   br label %for.body
508 for.body:
509   %sum.010 = phi i8 [ 0, %entry ], [ %add, %for.body ]
510   %p.09 = phi ptr [ %x, %entry ], [ %incdec.ptr, %for.body ]
511   %incdec.ptr = getelementptr inbounds i8, ptr %p.09, i64 1
512   %load = load volatile i8, ptr %p.09, align 1
513   %add = add i8 %load, %sum.010
514   %exitcond = icmp eq ptr %incdec.ptr, %lftr.limit
515   br i1 %exitcond, label %for.cond.cleanup, label %for.body
517 for.cond.cleanup:
518   ret i8 %add
521 define dso_local void @SizeCheck(i32 %sz) {
522 ; CHECK-LABEL: @SizeCheck{{$}}
523 ; CHECK-NEXT: args uses:
524 ; CHECK-NEXT: allocas uses:
525 ; CHECK-NEXT: x1[128]: [0,4294967295){{$}}
526 ; GLOBAL-NEXT: safe accesses:
527 ; CHECK-EMPTY:
528 entry:
529   %x1 = alloca [128 x i8], align 16
530   %cmp = icmp slt i32 %sz, 129
531   br i1 %cmp, label %if.then, label %if.end
533 if.then:
534   call void @llvm.memset.p0.i32(ptr nonnull align 16 %x1, i8 0, i32 %sz, i1 false)
535   br label %if.end
537 if.end:
538   ret void
541 ; FIXME: scalable allocas are considered to be of size zero, and scalable accesses to be full-range.
542 ; This effectively disables safety analysis for scalable allocations.
543 define void @Scalable(ptr %p, ptr %unused, <vscale x 4 x i32> %v) {
544 ; CHECK-LABEL: @Scalable dso_preemptable{{$}}
545 ; CHECK-NEXT: args uses:
546 ; CHECK-NEXT:   p[]: full-set
547 ; CHECK-NEXT:   unused[]: empty-set
548 ; CHECK-NEXT: allocas uses:
549 ; CHECK-NEXT:   x[0]: [0,1){{$}}
550 ; GLOBAL-NEXT: safe accesses:
551 ; GLOBAL-NEXT: store <vscale x 4 x i32> %v, ptr %p, align 4
552 ; CHECK-EMPTY:
553 entry:
554   %x = alloca <vscale x 4 x i32>, align 4
555   store i8 0, ptr %x, align 1
556   store <vscale x 4 x i32> %v, ptr %p, align 4
557   ret void
560 %zerosize_type = type {}
562 define void @ZeroSize(ptr %p)  {
563 ; CHECK-LABEL: @ZeroSize dso_preemptable{{$}}
564 ; CHECK-NEXT: args uses:
565 ; CHECK-NEXT:   p[]: empty-set
566 ; CHECK-NEXT: allocas uses:
567 ; CHECK-NEXT:   x[0]: empty-set
568 ; GLOBAL-NEXT: safe accesses:
569 ; GLOBAL-NEXT: store %zerosize_type undef, ptr %x, align 4
570 ; GLOBAL-NEXT: store %zerosize_type undef, ptr undef, align 4
571 ; GLOBAL-NEXT: load %zerosize_type, ptr %p, align
572 ; CHECK-EMPTY:
573 entry:
574   %x = alloca %zerosize_type, align 4
575   store %zerosize_type undef, ptr %x, align 4
576   store %zerosize_type undef, ptr undef, align 4
577   %val = load %zerosize_type, ptr %p, align 4
578   ret void
581 define void @OperandBundle() {
582 ; CHECK-LABEL: @OperandBundle dso_preemptable{{$}}
583 ; CHECK-NEXT: args uses:
584 ; CHECK-NEXT: allocas uses:
585 ; CHECK-NEXT:   a[4]: full-set
586 ; GLOBAL-NEXT: safe accesses:
587 ; CHECK-EMPTY:
588 entry:
589   %a = alloca i32, align 4
590   call void @LeakAddress() ["unknown"(ptr %a)]
591   ret void
594 define void @ByVal(ptr byval(i16) %p) {
595   ; CHECK-LABEL: @ByVal dso_preemptable{{$}}
596   ; CHECK-NEXT: args uses:
597   ; CHECK-NEXT: allocas uses:
598   ; GLOBAL-NEXT: safe accesses:
599   ; CHECK-EMPTY:
600 entry:
601   ret void
604 define void @TestByVal() {
605 ; CHECK-LABEL: @TestByVal dso_preemptable{{$}}
606 ; CHECK-NEXT: args uses:
607 ; CHECK-NEXT: allocas uses:
608 ; CHECK-NEXT: x[2]: [0,2)
609 ; CHECK-NEXT: y[8]: [0,2)
610 ; GLOBAL-NEXT: safe accesses:
611 ; GLOBAL-NEXT: call void @ByVal(ptr byval(i16) %x)
612 ; GLOBAL-NEXT: call void @ByVal(ptr byval(i16) %y)
613 ; CHECK-EMPTY:
614 entry:
615   %x = alloca i16, align 4
616   call void @ByVal(ptr byval(i16) %x)
618   %y = alloca i64, align 4
619   call void @ByVal(ptr byval(i16) %y)
621   ret void
624 declare void @ByValArray(ptr byval([100000 x i64]) %p)
626 define void @TestByValArray() {
627 ; CHECK-LABEL: @TestByValArray dso_preemptable{{$}}
628 ; CHECK-NEXT: args uses:
629 ; CHECK-NEXT: allocas uses:
630 ; CHECK-NEXT: z[800000]: [500000,1300000)
631 ; GLOBAL-NEXT: safe accesses:
632 ; CHECK-EMPTY:
633 entry:
634   %z = alloca [100000 x i64], align 4
635   %z2 = getelementptr i8, ptr %z, i64 500000
636   call void @ByValArray(ptr byval([100000 x i64]) %z2)
637   ret void
640 define dso_local i8 @LoadMinInt64(ptr %p) {
641   ; CHECK-LABEL: @LoadMinInt64{{$}}
642   ; CHECK-NEXT: args uses:
643   ; CHECK-NEXT: p[]: [-9223372036854775808,-9223372036854775807){{$}}
644   ; CHECK-NEXT: allocas uses:
645   ; GLOBAL-NEXT: safe accesses:
646   ; GLOBAL-NEXT: load i8, ptr %p2, align 1
647   ; CHECK-EMPTY:
648   %p2 = getelementptr i8, ptr %p, i64 -9223372036854775808
649   %v = load i8, ptr %p2, align 1
650   ret i8 %v
653 define void @Overflow() {
654 ; CHECK-LABEL: @Overflow dso_preemptable{{$}}
655 ; CHECK-NEXT: args uses:
656 ; CHECK-NEXT: allocas uses:
657 ; LOCAL-NEXT: x[1]: empty-set, @LoadMinInt64(arg0, [-9223372036854775808,-9223372036854775807)){{$}}
658 ; GLOBAL-NEXT: x[1]: full-set, @LoadMinInt64(arg0, [-9223372036854775808,-9223372036854775807)){{$}}
659 ; GLOBAL-NEXT: safe accesses:
660 ; CHECK-EMPTY:
661 entry:
662   %x = alloca i8, align 4
663   %x2 = getelementptr i8, ptr %x, i64 -9223372036854775808
664   %v = call i8 @LoadMinInt64(ptr %x2)
665   ret void
668 define void @DeadBlock(ptr %p) {
669 ; CHECK-LABEL: @DeadBlock dso_preemptable{{$}}
670 ; CHECK-NEXT: args uses:
671 ; CHECK-NEXT: p[]: empty-set{{$}}
672 ; CHECK-NEXT: allocas uses:
673 ; CHECK-NEXT: x[1]: empty-set{{$}}
674 ; GLOBAL-NEXT: safe accesses:
675 ; GLOBAL-NEXT: store i8 5, ptr %x
676 ; GLOBAL-NEXT: store i64 -5, ptr %p
677 ; CHECK-EMPTY:
678 entry:
679   %x = alloca i8, align 4
680   br label %end
682 dead:
683   store i8 5, ptr %x
684   store i64 -5, ptr %p
685   br label %end
687 end:
688   ret void
691 define void @LifeNotStarted() {
692 ; CHECK-LABEL: @LifeNotStarted dso_preemptable{{$}}
693 ; CHECK-NEXT: args uses:
694 ; CHECK-NEXT: allocas uses:
695 ; CHECK: x[1]: full-set{{$}}
696 ; CHECK: y[1]: full-set{{$}}
697 ; CHECK: z[1]: full-set{{$}}
698 ; GLOBAL-NEXT: safe accesses:
699 ; CHECK-EMPTY:
700 entry:
701   %x = alloca i8, align 4
702   %y = alloca i8, align 4
703   %z = alloca i8, align 4
705   store i8 5, ptr %x
706   %n = load i8, ptr %y
707   call void @llvm.memset.p0.i32(ptr nonnull %z, i8 0, i32 1, i1 false)
709   call void @llvm.lifetime.start.p0(i64 1, ptr %x)
710   call void @llvm.lifetime.start.p0(i64 1, ptr %y)
711   call void @llvm.lifetime.start.p0(i64 1, ptr %z)
713   ret void
716 define void @LifeOK() {
717 ; CHECK-LABEL: @LifeOK dso_preemptable{{$}}
718 ; CHECK-NEXT: args uses:
719 ; CHECK-NEXT: allocas uses:
720 ; CHECK: x[1]: [0,1){{$}}
721 ; CHECK: y[1]: [0,1){{$}}
722 ; CHECK: z[1]: [0,1){{$}}
723 ; GLOBAL-NEXT: safe accesses:
724 ; GLOBAL-NEXT: store i8 5, ptr %x
725 ; GLOBAL-NEXT: %n = load i8, ptr %y
726 ; GLOBAL-NEXT: call void @llvm.memset.p0.i32(ptr nonnull %z, i8 0, i32 1, i1 false)
727 ; CHECK-EMPTY:
728 entry:
729   %x = alloca i8, align 4
730   %y = alloca i8, align 4
731   %z = alloca i8, align 4
733   call void @llvm.lifetime.start.p0(i64 1, ptr %x)
734   call void @llvm.lifetime.start.p0(i64 1, ptr %y)
735   call void @llvm.lifetime.start.p0(i64 1, ptr %z)
737   store i8 5, ptr %x
738   %n = load i8, ptr %y
739   call void @llvm.memset.p0.i32(ptr nonnull %z, i8 0, i32 1, i1 false)
741   ret void
744 define void @LifeEnded() {
745 ; CHECK-LABEL: @LifeEnded dso_preemptable{{$}}
746 ; CHECK-NEXT: args uses:
747 ; CHECK-NEXT: allocas uses:
748 ; CHECK: x[1]: full-set{{$}}
749 ; CHECK: y[1]: full-set{{$}}
750 ; CHECK: z[1]: full-set{{$}}
751 ; GLOBAL-NEXT: safe accesses:
752 ; CHECK-EMPTY:
753 entry:
754   %x = alloca i8, align 4
755   %y = alloca i8, align 4
756   %z = alloca i8, align 4
758   call void @llvm.lifetime.start.p0(i64 1, ptr %x)
759   call void @llvm.lifetime.start.p0(i64 1, ptr %y)
760   call void @llvm.lifetime.start.p0(i64 1, ptr %z)
762   call void @llvm.lifetime.end.p0(i64 1, ptr %x)
763   call void @llvm.lifetime.end.p0(i64 1, ptr %y)
764   call void @llvm.lifetime.end.p0(i64 1, ptr %z)
766   store i8 5, ptr %x
767   %n = load i8, ptr %y
768   call void @llvm.memset.p0.i32(ptr nonnull %z, i8 0, i32 1, i1 false)
770   ret void
773 define void @TwoAllocasOK() {
774 ; CHECK-LABEL: @TwoAllocasOK
775 ; CHECK-NEXT: args uses:
776 ; CHECK-NEXT: allocas uses:
777 ; CHECK: a[4]: [0,1){{$}}
778 ; CHECK: y[1]: [0,1){{$}}
779 ; GLOBAL-NEXT: safe accesses:
780 ; GLOBAL-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr %y, ptr %a, i32 1, i1 false)
781 ; CHECK-EMPTY:
782 entry:
783   %a = alloca i32, align 4
784   %y = alloca i8, align 4
785   call void @llvm.memcpy.p0.p0.i32(ptr %y, ptr %a, i32 1, i1 false)
786   ret void
789 define void @TwoAllocasOOBDest() {
790 ; CHECK-LABEL: @TwoAllocasOOBDest
791 ; CHECK-NEXT: args uses:
792 ; CHECK-NEXT: allocas uses:
793 ; CHECK: a[4]: [0,4){{$}}
794 ; CHECK: y[1]: [0,4){{$}}
795 ; GLOBAL-NEXT: safe accesses:
796 ; CHECK-EMPTY:
797 entry:
798   %a = alloca i32, align 4
799   %y = alloca i8, align 4
800   call void @llvm.memcpy.p0.p0.i32(ptr %y, ptr %a, i32 4, i1 false)
801   ret void
804 define void @TwoAllocasOOBSource() {
805 ; CHECK-LABEL: @TwoAllocasOOBSource
806 ; CHECK-NEXT: args uses:
807 ; CHECK-NEXT: allocas uses:
808 ; CHECK: a[4]: [0,4){{$}}
809 ; CHECK: y[1]: [0,4){{$}}
810 ; GLOBAL-NEXT: safe accesses:
811 ; CHECK-EMPTY:
812 entry:
813   %a = alloca i32, align 4
814   %y = alloca i8, align 4
815   call void @llvm.memcpy.p0.p0.i32(ptr %a, ptr %y, i32 4, i1 false)
816   ret void
819 define void @TwoAllocasOOBBoth() {
820 ; CHECK-LABEL: @TwoAllocasOOBBoth
821 ; CHECK-NEXT: args uses:
822 ; CHECK-NEXT: allocas uses:
823 ; CHECK: a[4]: [0,5){{$}}
824 ; CHECK: y[1]: [0,5){{$}}
825 ; GLOBAL-NEXT: safe accesses:
826 ; CHECK-EMPTY:
827 entry:
828   %a = alloca i32, align 4
829   %y = alloca i8, align 4
830   call void @llvm.memcpy.p0.p0.i32(ptr %y, ptr %a, i32 5, i1 false)
831   ret void
834 define void @MixedAccesses() {
835 ; CHECK-LABEL: @MixedAccesses
836 ; CHECK-NEXT: args uses:
837 ; CHECK-NEXT: allocas uses:
838 ; CHECK: a[4]: [0,5){{$}}
839 ; GLOBAL-NEXT: safe accesses:
840 ; GLOBAL-NEXT: call void @llvm.memset.p0.i32(ptr %a, i8 1, i32 4, i1 false)
841 ; CHECK-EMPTY:
842 entry:
843   %a = alloca i32, align 4
844   call void @llvm.memset.p0.i32(ptr %a, i8 1, i32 5, i1 false)
845   call void @llvm.memset.p0.i32(ptr %a, i8 1, i32 4, i1 false)
846   ret void
849 define void @MixedAccesses2() {
850 ; CHECK-LABEL: @MixedAccesses2
851 ; CHECK-NEXT: args uses:
852 ; CHECK-NEXT: allocas uses:
853 ; CHECK: a[4]: [0,8){{$}}
854 ; GLOBAL-NEXT: safe accesses:
855 ; GLOBAL-NEXT: load i32, ptr %a, align 4
856 ; CHECK-EMPTY:
857 entry:
858   %a = alloca i32, align 4
859   %n1 = load i64, ptr %a, align 4
860   %n2 = load i32, ptr %a, align 4
861   ret void
864 define void @MixedAccesses3(ptr %func) {
865 ; CHECK-LABEL: @MixedAccesses3
866 ; CHECK-NEXT: args uses:
867 ; CHECK-NEXT: func[]: full-set
868 ; CHECK-NEXT: allocas uses:
869 ; CHECK: a[4]: full-set{{$}}
870 ; GLOBAL-NEXT: safe accesses:
871 ; GLOBAL-NEXT: load i32, ptr %a, align 4
872 ; CHECK-EMPTY:
873 entry:
874   %a = alloca i32, align 4
875   %n2 = load i32, ptr %a, align 4
876   call void %func(ptr %a)
877   ret void
880 define void @MixedAccesses4() {
881 ; CHECK-LABEL: @MixedAccesses4
882 ; CHECK-NEXT: args uses:
883 ; CHECK-NEXT: allocas uses:
884 ; CHECK: a[4]: full-set{{$}}
885 ; CHECK: a1[8]: [0,8){{$}}
886 ; GLOBAL-NEXT: safe accesses:
887 ; GLOBAL-NEXT: load i32, ptr %a, align 4
888 ; CHECK-EMPTY:
889 entry:
890   %a = alloca i32, align 4
891   %a1 = alloca ptr, align 4
892   %n2 = load i32, ptr %a, align 4
893   store ptr %a, ptr %a1
894   ret void
897 define ptr @MixedAccesses5(i1 %x, ptr %y) {
898 ; CHECK-LABEL: @MixedAccesses5
899 ; CHECK-NEXT: args uses:
900 ; CHECK: y[]: full-set
901 ; CHECK-NEXT: allocas uses:
902 ; CHECK: a[4]: full-set{{$}}
903 ; GLOBAL-NEXT: safe accesses:
904 ; GLOBAL-NEXT: load i32, ptr %a, align 4
905 ; CHECK-EMPTY:
906 entry:
907   %a = alloca i32, align 4
908   br i1 %x, label %tlabel, label %flabel
909 flabel:
910   %n = load i32, ptr %a, align 4
911   ret ptr %y
912 tlabel:
913   ret ptr %a
916 define void @MixedAccesses6(ptr %arg) {
917 ; CHECK-LABEL: @MixedAccesses6
918 ; CHECK-NEXT: args uses:
919 ; CHECK-NEXT: arg[]: [0,4)
920 ; CHECK-NEXT: allocas uses:
921 ; CHECK: a[4]: [0,4)
922 ; GLOBAL-NEXT: safe accesses:
923 ; GLOBAL-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr %a, ptr %arg, i32 4, i1 false)
924 ; CHECK-EMPTY:
925 entry:
926   %a = alloca i32, align 4
927   call void @llvm.memcpy.p0.p0.i32(ptr %a, ptr %arg, i32 4, i1 false)
928   ret void
931 define void @MixedAccesses7(i1 %cond, ptr %arg) {
932 ; SECV doesn't support select, so we consider this non-stack-safe, even through
933 ; it is.
935 ; CHECK-LABEL: @MixedAccesses7
936 ; CHECK-NEXT: args uses:
937 ; CHECK-NEXT: arg[]: full-set
938 ; CHECK-NEXT: allocas uses:
939 ; CHECK: a[4]: full-set
940 ; GLOBAL-NEXT: safe accesses:
941 ; CHECK-EMPTY:
942 entry:
943   %a = alloca i32, align 4
944   %x1 = select i1 %cond, ptr %arg, ptr %a
945   call void @llvm.memcpy.p0.p0.i32(ptr %x1, ptr %arg, i32 4, i1 false)
946   ret void
949 define void @NoStackAccess(ptr %arg1, ptr %arg2) {
950 ; CHECK-LABEL: @NoStackAccess
951 ; CHECK-NEXT: args uses:
952 ; CHECK-NEXT: arg1[]: [0,4)
953 ; CHECK-NEXT: arg2[]: [0,4)
954 ; CHECK-NEXT: allocas uses:
955 ; CHECK: a[4]: empty-set{{$}}
956 ; GLOBAL-NEXT: safe accesses:
957 ; GLOBAL-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr %arg1, ptr %arg2, i32 4, i1 false)
958 ; CHECK-EMPTY:
959 entry:
960   %a = alloca i32, align 4
961   call void @llvm.memcpy.p0.p0.i32(ptr %arg1, ptr %arg2, i32 4, i1 false)
962   ret void
965 define void @DoubleLifetime() {
966 ; CHECK-LABEL: @DoubleLifetime
967 ; CHECK-NEXT: args uses:
968 ; CHECK-NEXT: allocas uses:
969 ; CHECK: a[4]: full-set{{$}}
970 ; GLOBAL-NEXT: safe accesses:
971 ; GLOBAL-NEXT: call void @llvm.memset.p0.i32(ptr %a, i8 1, i32 4, i1 false)
972 ; CHECK-EMPTY:
973 entry:
974   %a = alloca i32, align 4
975   call void @llvm.lifetime.start.p0(i64 4, ptr %a)
976   call void @llvm.lifetime.end.p0(i64 4, ptr %a)
977   call void @llvm.memset.p0.i32(ptr %a, i8 1, i32 4, i1 true)
979   call void @llvm.lifetime.start.p0(i64 4, ptr %a)
980   call void @llvm.memset.p0.i32(ptr %a, i8 1, i32 4, i1 false)
981   call void @llvm.lifetime.end.p0(i64 4, ptr %a)
982   ret void
985 define void @DoubleLifetime2() {
986 ; CHECK-LABEL: @DoubleLifetime2
987 ; CHECK-NEXT: args uses:
988 ; CHECK-NEXT: allocas uses:
989 ; CHECK: a[4]: full-set{{$}}
990 ; GLOBAL-NEXT: safe accesses:
991 ; GLOBAL-NEXT: call void @llvm.memset.p0.i32(ptr %a, i8 1, i32 4, i1 false)
992 ; CHECK-EMPTY:
993 entry:
994   %a = alloca i32, align 4
995   call void @llvm.lifetime.start.p0(i64 4, ptr %a)
996   call void @llvm.lifetime.end.p0(i64 4, ptr %a)
997   %n = load i32, ptr %a
999   call void @llvm.lifetime.start.p0(i64 4, ptr %a)
1000   call void @llvm.memset.p0.i32(ptr %a, i8 1, i32 4, i1 false)
1001   call void @llvm.lifetime.end.p0(i64 4, ptr %a)
1002   ret void
1005 define void @DoubleLifetime3() {
1006 ; CHECK-LABEL: @DoubleLifetime3
1007 ; CHECK-NEXT: args uses:
1008 ; CHECK-NEXT: allocas uses:
1009 ; CHECK: a[4]: full-set{{$}}
1010 ; GLOBAL-NEXT: safe accesses:
1011 ; GLOBAL-NEXT: call void @llvm.memset.p0.i32(ptr %a, i8 1, i32 4, i1 false)
1012 ; CHECK-EMPTY:
1013 entry:
1014   %a = alloca i32, align 4
1015   call void @llvm.lifetime.start.p0(i64 4, ptr %a)
1016   call void @llvm.lifetime.end.p0(i64 4, ptr %a)
1017   store i32 5, ptr %a
1019   call void @llvm.lifetime.start.p0(i64 4, ptr %a)
1020   call void @llvm.memset.p0.i32(ptr %a, i8 1, i32 4, i1 false)
1021   call void @llvm.lifetime.end.p0(i64 4, ptr %a)
1022   ret void
1025 define void @DoubleLifetime4() {
1026 ; CHECK-LABEL: @DoubleLifetime4
1027 ; CHECK-NEXT: args uses:
1028 ; CHECK-NEXT: allocas uses:
1029 ; CHECK: a[4]: full-set{{$}}
1030 ; GLOBAL-NEXT: safe accesses:
1031 ; GLOBAL-NEXT: call void @llvm.memset.p0.i32(ptr %a, i8 1, i32 4, i1 false)
1032 ; CHECK-EMPTY:
1033 entry:
1034   %a = alloca i32, align 4
1035   call void @llvm.lifetime.start.p0(i64 4, ptr %a)
1036   call void @llvm.memset.p0.i32(ptr %a, i8 1, i32 4, i1 false)
1037   call void @llvm.lifetime.end.p0(i64 4, ptr %a)
1038   call void @unknown_call(ptr %a)
1039   ret void
1042 define void @Cmpxchg4Arg(ptr %p) {
1043 ; CHECK-LABEL: @Cmpxchg4Arg
1044 ; CHECK-NEXT: args uses:
1045 ; CHECK-NEXT: p[]: [0,4){{$}}
1046 ; CHECK-NEXT: allocas uses:
1047 ; GLOBAL-NEXT: safe accesses:
1048 ; GLOBAL-NEXT: cmpxchg ptr %p, i32 0, i32 1 monotonic monotonic, align 1
1049 ; CHECK-EMPTY:
1050 entry:
1051   cmpxchg ptr %p, i32 0, i32 1 monotonic monotonic, align 1
1052   ret void
1055 define void @AtomicRMW4Arg(ptr %p) {
1056 ; CHECK-LABEL: @AtomicRMW4Arg
1057 ; CHECK-NEXT: args uses:
1058 ; CHECK-NEXT: p[]: [0,4){{$}}
1059 ; CHECK-NEXT: allocas uses:
1060 ; GLOBAL-NEXT: safe accesses:
1061 ; GLOBAL-NEXT: atomicrmw add ptr %p, i32 1 monotonic, align 1
1062 ; CHECK-EMPTY:
1063 entry:
1064   atomicrmw add ptr %p, i32 1 monotonic, align 1
1065   ret void
1068 define void @Cmpxchg4Alloca() {
1069 ; CHECK-LABEL: @Cmpxchg4Alloca
1070 ; CHECK-NEXT: args uses:
1071 ; CHECK-NEXT: allocas uses:
1072 ; CHECK-NEXT: x[4]: [0,4){{$}}
1073 ; GLOBAL-NEXT: safe accesses:
1074 ; GLOBAL-NEXT: cmpxchg ptr %x, i32 0, i32 1 monotonic monotonic, align 1
1075 ; CHECK-EMPTY:
1076 entry:
1077   %x = alloca i32, align 4
1078   cmpxchg ptr %x, i32 0, i32 1 monotonic monotonic, align 1
1079   ret void
1082 define void @AtomicRMW4Alloca() {
1083 ; CHECK-LABEL: @AtomicRMW4Alloca
1084 ; CHECK-NEXT: args uses:
1085 ; CHECK-NEXT: allocas uses:
1086 ; CHECK-NEXT: x[4]: [0,4){{$}}
1087 ; GLOBAL-NEXT: safe accesses:
1088 ; GLOBAL-NEXT: atomicrmw add ptr %x, i32 1 monotonic, align 1
1089 ; CHECK-EMPTY:
1090 entry:
1091   %x = alloca i32, align 4
1092   atomicrmw add ptr %x, i32 1 monotonic, align 1
1093   ret void
1096 define void @StoreArg(ptr %p) {
1097 ; CHECK-LABEL: @StoreArg
1098 ; CHECK-NEXT: args uses:
1099 ; CHECK-NEXT: p[]: [0,4){{$}}
1100 ; CHECK-NEXT: allocas uses:
1101 ; GLOBAL-NEXT: safe accesses:
1102 ; GLOBAL-NEXT: store i32 1, ptr %p
1103 ; CHECK-EMPTY:
1104 entry:
1105   store i32 1, ptr %p
1106   ret void
1109 declare void @llvm.lifetime.start.p0(i64, ptr nocapture)
1110 declare void @llvm.lifetime.end.p0(i64, ptr nocapture)