1141 lines · plain
1; RUN: opt -S -passes="print<stack-safety-local>" -disable-output < %s 2>&1 | FileCheck %s --check-prefixes=CHECK,LOCAL2; RUN: opt -S -passes="print-stack-safety" -disable-output < %s 2>&1 | FileCheck %s --check-prefixes=CHECK,GLOBAL3 4target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"5target triple = "x86_64-unknown-linux-gnu"6 7@sink = global ptr null, align 88 9declare void @llvm.memset.p0.i32(ptr %dest, i8 %val, i32 %len, i1 %isvolatile)10declare void @llvm.memcpy.p0.p0.i32(ptr %dest, ptr %src, i32 %len, i1 %isvolatile)11declare void @llvm.memmove.p0.p0.i32(ptr %dest, ptr %src, i32 %len, i1 %isvolatile)12declare void @llvm.memset.p0.i64(ptr %dest, i8 %val, i64 %len, i1 %isvolatile)13 14declare void @unknown_call(ptr %dest)15declare void @unknown_call_int(i64 %i)16declare ptr @retptr(ptr returned)17 18; Address leaked.19define void @LeakAddress() {20; CHECK-LABEL: @LeakAddress dso_preemptable{{$}}21; CHECK-NEXT: args uses:22; CHECK-NEXT: allocas uses:23; CHECK-NEXT: x[4]: full-set{{$}}24; GLOBAL-NEXT: safe accesses:25; CHECK-EMPTY:26entry:27 %x = alloca i32, align 428 store ptr %x, ptr @sink, align 829 ret void30}31 32define void @StoreInBounds() {33; CHECK-LABEL: @StoreInBounds dso_preemptable{{$}}34; CHECK-NEXT: args uses:35; CHECK-NEXT: allocas uses:36; CHECK-NEXT: x[4]: [0,1){{$}}37; GLOBAL-NEXT: safe accesses:38; GLOBAL-NEXT: store i8 0, ptr %x, align 139; CHECK-EMPTY:40entry:41 %x = alloca i32, align 442 store i8 0, ptr %x, align 143 ret void44}45 46define void @StoreInBoundsCond(i64 %i) {47; CHECK-LABEL: @StoreInBoundsCond dso_preemptable{{$}}48; CHECK-NEXT: args uses:49; CHECK-NEXT: allocas uses:50; CHECK-NEXT: x[4]: full-set{{$}}51; GLOBAL-NEXT: safe accesses:52; GLOBAL-NEXT: store i8 0, ptr %x2, align 153; CHECK-EMPTY:54entry:55 %x = alloca i32, align 456 %c1 = icmp sge i64 %i, 057 %c2 = icmp slt i64 %i, 458 br i1 %c1, label %c1.true, label %false59 60c1.true:61 br i1 %c2, label %c2.true, label %false62 63c2.true:64 %x2 = getelementptr i8, ptr %x, i64 %i65 store i8 0, ptr %x2, align 166 br label %false67 68false:69 ret void70}71 72define void @StoreInBoundsMinMax(i64 %i) {73; CHECK-LABEL: @StoreInBoundsMinMax dso_preemptable{{$}}74; CHECK-NEXT: args uses:75; CHECK-NEXT: allocas uses:76; CHECK-NEXT: x[4]: [0,4){{$}}77; GLOBAL-NEXT: safe accesses:78; GLOBAL-NEXT: store i8 0, ptr %x2, align 179; CHECK-EMPTY:80entry:81 %x = alloca i32, align 482 %c1 = icmp sge i64 %i, 083 %i1 = select i1 %c1, i64 %i, i64 084 %c2 = icmp slt i64 %i1, 385 %i2 = select i1 %c2, i64 %i1, i64 386 %x2 = getelementptr i8, ptr %x, i64 %i287 store i8 0, ptr %x2, align 188 ret void89}90 91define void @StoreInBounds2() {92; CHECK-LABEL: @StoreInBounds2 dso_preemptable{{$}}93; CHECK-NEXT: args uses:94; CHECK-NEXT: allocas uses:95; CHECK-NEXT: x[4]: [0,4){{$}}96; GLOBAL-NEXT: safe accesses:97; GLOBAL-NEXT: store i32 0, ptr %x, align 498; CHECK-EMPTY:99entry:100 %x = alloca i32, align 4101 store i32 0, ptr %x, align 4102 ret void103}104 105define void @StoreInBounds3() {106; CHECK-LABEL: @StoreInBounds3 dso_preemptable{{$}}107; CHECK-NEXT: args uses:108; CHECK-NEXT: allocas uses:109; CHECK-NEXT: x[4]: [2,3){{$}}110; GLOBAL-NEXT: safe accesses:111; GLOBAL-NEXT: store i8 0, ptr %x2, align 1112; CHECK-EMPTY:113entry:114 %x = alloca i32, align 4115 %x2 = getelementptr i8, ptr %x, i64 2116 store i8 0, ptr %x2, align 1117 ret void118}119 120; FIXME: ScalarEvolution does not look through ptrtoint/inttoptr.121define void @StoreInBounds4() {122; CHECK-LABEL: @StoreInBounds4 dso_preemptable{{$}}123; CHECK-NEXT: args uses:124; CHECK-NEXT: allocas uses:125; CHECK-NEXT: x[4]: full-set{{$}}126; GLOBAL-NEXT: safe accesses:127; CHECK-EMPTY:128entry:129 %x = alloca i32, align 4130 %x1 = ptrtoint ptr %x to i64131 %x2 = add i64 %x1, 2132 %x3 = inttoptr i64 %x2 to ptr133 store i8 0, ptr %x3, align 1134 ret void135}136 137define void @StoreInBounds6() {138; CHECK-LABEL: @StoreInBounds6 dso_preemptable{{$}}139; CHECK-NEXT: args uses:140; CHECK-NEXT: allocas uses:141; GLOBAL-NEXT: x[4]: full-set, @retptr(arg0, [0,1)){{$}}142; LOCAL-NEXT: x[4]: [0,1), @retptr(arg0, [0,1)){{$}}143; GLOBAL-NEXT: safe accesses:144; GLOBAL-NEXT: store i8 0, ptr %x2, align 1145; CHECK-EMPTY:146entry:147 %x = alloca i32, align 4148 %x2 = call ptr @retptr(ptr %x)149 store i8 0, ptr %x2, align 1150 ret void151}152 153define dso_local void @WriteMinMax(ptr %p) {154; CHECK-LABEL: @WriteMinMax{{$}}155; CHECK-NEXT: args uses:156; CHECK-NEXT: p[]: full-set157; CHECK-NEXT: allocas uses:158; GLOBAL-NEXT: safe accesses:159; GLOBAL-NEXT: store i8 0, ptr %p1, align 1160; GLOBAL-NEXT: store i8 0, ptr %p2, align 1161; CHECK-EMPTY:162entry:163 %p1 = getelementptr i8, ptr %p, i64 9223372036854775805164 store i8 0, ptr %p1, align 1165 %p2 = getelementptr i8, ptr %p, i64 -9223372036854775805166 store i8 0, ptr %p2, align 1167 ret void168}169 170define dso_local void @WriteMax(ptr %p) {171; CHECK-LABEL: @WriteMax{{$}}172; CHECK-NEXT: args uses:173; CHECK-NEXT: p[]: [-9223372036854775807,9223372036854775806)174; CHECK-NEXT: allocas uses:175; GLOBAL-NEXT: safe accesses:176; GLOBAL-NEXT: call void @llvm.memset.p0.i64(ptr %p, i8 1, i64 9223372036854775806, i1 false)177; GLOBAL-NEXT: call void @llvm.memset.p0.i64(ptr %p2, i8 1, i64 9223372036854775806, i1 false)178; CHECK-EMPTY:179entry:180 call void @llvm.memset.p0.i64(ptr %p, i8 1, i64 9223372036854775806, i1 0)181 %p2 = getelementptr i8, ptr %p, i64 -9223372036854775807182 call void @llvm.memset.p0.i64(ptr %p2, i8 1, i64 9223372036854775806, i1 0)183 ret void184}185 186define void @StoreOutOfBounds() {187; CHECK-LABEL: @StoreOutOfBounds dso_preemptable{{$}}188; CHECK-NEXT: args uses:189; CHECK-NEXT: allocas uses:190; CHECK-NEXT: x[4]: [2,6){{$}}191; GLOBAL-NEXT: safe accesses:192; CHECK-EMPTY:193entry:194 %x = alloca i32, align 4195 %x2 = getelementptr i8, ptr %x, i64 2196 store i32 0, ptr %x2, align 1197 ret void198}199 200define void @StoreOutOfBoundsCond(i64 %i) {201; CHECK-LABEL: @StoreOutOfBoundsCond dso_preemptable{{$}}202; CHECK-NEXT: args uses:203; CHECK-NEXT: allocas uses:204; CHECK-NEXT: x[4]: full-set{{$}}205; GLOBAL-NEXT: safe accesses:206; CHECK-EMPTY:207entry:208 %x = alloca i32, align 4209 %c1 = icmp sge i64 %i, 0210 %c2 = icmp slt i64 %i, 5211 br i1 %c1, label %c1.true, label %false212 213c1.true:214 br i1 %c2, label %c2.true, label %false215 216c2.true:217 %x2 = getelementptr i8, ptr %x, i64 %i218 store i8 0, ptr %x2, align 1219 br label %false220 221false:222 ret void223}224 225define void @StoreOutOfBoundsCond2(i64 %i) {226; CHECK-LABEL: @StoreOutOfBoundsCond2 dso_preemptable{{$}}227; CHECK-NEXT: args uses:228; CHECK-NEXT: allocas uses:229; CHECK-NEXT: x[4]: full-set{{$}}230; GLOBAL-NEXT: safe accesses:231; CHECK-EMPTY:232entry:233 %x = alloca i32, align 4234 %c2 = icmp slt i64 %i, 5235 br i1 %c2, label %c2.true, label %false236 237c2.true:238 %x2 = getelementptr i8, ptr %x, i64 %i239 store i8 0, ptr %x2, align 1240 br label %false241 242false:243 ret void244}245 246define void @StoreOutOfBounds2() {247; CHECK-LABEL: @StoreOutOfBounds2 dso_preemptable{{$}}248; CHECK-NEXT: args uses:249; CHECK-NEXT: allocas uses:250; GLOBAL-NEXT: x[4]: full-set, @retptr(arg0, [2,3)){{$}}251; LOCAL-NEXT: x[4]: [2,6), @retptr(arg0, [2,3)){{$}}252; GLOBAL-NEXT: safe accesses:253; CHECK-EMPTY:254entry:255 %x = alloca i32, align 4256 %x2 = getelementptr i8, ptr %x, i64 2257 %x3 = call ptr @retptr(ptr %x2)258 store i32 0, ptr %x3, align 1259 ret void260}261 262; There is no difference in load vs store handling.263define void @LoadInBounds() {264; CHECK-LABEL: @LoadInBounds dso_preemptable{{$}}265; CHECK-NEXT: args uses:266; CHECK-NEXT: allocas uses:267; CHECK-NEXT: x[4]: [0,1){{$}}268; GLOBAL-NEXT: safe accesses:269; GLOBAL-NEXT: %v = load i8, ptr %x, align 1270; CHECK-EMPTY:271entry:272 %x = alloca i32, align 4273 %v = load i8, ptr %x, align 1274 ret void275}276 277define void @LoadOutOfBounds() {278; CHECK-LABEL: @LoadOutOfBounds dso_preemptable{{$}}279; CHECK-NEXT: args uses:280; CHECK-NEXT: allocas uses:281; CHECK-NEXT: x[4]: [2,6){{$}}282; GLOBAL-NEXT: safe accesses:283; CHECK-EMPTY:284entry:285 %x = alloca i32, align 4286 %x2 = getelementptr i8, ptr %x, i64 2287 %v = load i32, ptr %x2, align 1288 ret void289}290 291; Leak through ret.292define ptr @Ret() {293; CHECK-LABEL: @Ret dso_preemptable{{$}}294; CHECK-NEXT: args uses:295; CHECK-NEXT: allocas uses:296; CHECK-NEXT: x[4]: full-set{{$}}297; GLOBAL-NEXT: safe accesses:298; CHECK-EMPTY:299entry:300 %x = alloca i32, align 4301 %x2 = getelementptr i8, ptr %x, i64 2302 ret ptr %x2303}304 305declare void @Foo(ptr %p)306 307define void @DirectCall() {308; CHECK-LABEL: @DirectCall dso_preemptable{{$}}309; CHECK-NEXT: args uses:310; CHECK-NEXT: allocas uses:311; LOCAL-NEXT: x[8]: empty-set, @Foo(arg0, [2,3)){{$}}312; GLOBAL-NEXT: x[8]: full-set, @Foo(arg0, [2,3)){{$}}313; GLOBAL-NEXT: safe accesses:314; CHECK-EMPTY:315entry:316 %x = alloca i64, align 4317 %x2 = getelementptr i16, ptr %x, i64 1318 call void @Foo(ptr %x2);319 ret void320}321 322; Indirect calls can not be analyzed (yet).323; FIXME: %p[]: full-set looks invalid324define void @IndirectCall(ptr %p) {325; CHECK-LABEL: @IndirectCall dso_preemptable{{$}}326; CHECK-NEXT: args uses:327; CHECK-NEXT: p[]: full-set{{$}}328; CHECK-NEXT: allocas uses:329; CHECK-NEXT: x[4]: full-set{{$}}330; GLOBAL-NEXT: safe accesses:331; CHECK-EMPTY:332entry:333 %x = alloca i32, align 4334 call void %p(ptr %x);335 ret void336}337 338define void @NonConstantOffset(i1 zeroext %z) {339; CHECK-LABEL: @NonConstantOffset dso_preemptable{{$}}340; CHECK-NEXT: args uses:341; CHECK-NEXT: allocas uses:342; FIXME: SCEV can't look through selects.343; CHECK-NEXT: x[4]: [0,4){{$}}344; GLOBAL-NEXT: safe accesses:345; GLOBAL-NEXT: store i8 0, ptr %x2, align 1346; CHECK-EMPTY:347entry:348 %x = alloca i32, align 4349 %idx = select i1 %z, i64 1, i64 2350 %x2 = getelementptr i8, ptr %x, i64 %idx351 store i8 0, ptr %x2, align 1352 ret void353}354 355define void @NegativeOffset() {356; CHECK-LABEL: @NegativeOffset dso_preemptable{{$}}357; CHECK-NEXT: args uses:358; CHECK-NEXT: allocas uses:359; CHECK-NEXT: x[40]: [-1600000000000,-1599999999996){{$}}360; GLOBAL-NEXT: safe accesses:361; CHECK-EMPTY:362entry:363 %x = alloca i32, i32 10, align 4364 %x2 = getelementptr i32, ptr %x, i64 -400000000000365 store i32 0, ptr %x2, align 1366 ret void367}368 369define void @PossiblyNegativeOffset(i16 %z) {370; CHECK-LABEL: @PossiblyNegativeOffset dso_preemptable{{$}}371; CHECK-NEXT: args uses:372; CHECK-NEXT: allocas uses:373; CHECK-NEXT: x[40]: [-131072,131072){{$}}374; GLOBAL-NEXT: safe accesses:375; CHECK-EMPTY:376entry:377 %x = alloca i32, i32 10, align 4378 %x2 = getelementptr i32, ptr %x, i16 %z379 store i32 0, ptr %x2, align 1380 ret void381}382 383define void @NonConstantOffsetOOB(i1 zeroext %z) {384; CHECK-LABEL: @NonConstantOffsetOOB dso_preemptable{{$}}385; CHECK-NEXT: args uses:386; CHECK-NEXT: allocas uses:387; CHECK-NEXT: x[4]: [0,6){{$}}388; GLOBAL-NEXT: safe accesses:389; CHECK-EMPTY:390entry:391 %x = alloca i32, align 4392 %idx = select i1 %z, i64 1, i64 4393 %x2 = getelementptr i8, ptr %x, i64 %idx394 store i8 0, ptr %x2, align 1395 ret void396}397 398define void @ArrayAlloca() {399; CHECK-LABEL: @ArrayAlloca dso_preemptable{{$}}400; CHECK-NEXT: args uses:401; CHECK-NEXT: allocas uses:402; CHECK-NEXT: x[40]: [36,40){{$}}403; GLOBAL-NEXT: safe accesses:404; GLOBAL-NEXT: store i32 0, ptr %x2, align 1405; CHECK-EMPTY:406entry:407 %x = alloca i32, i32 10, align 4408 %x2 = getelementptr i8, ptr %x, i64 36409 store i32 0, ptr %x2, align 1410 ret void411}412 413define void @ArrayAllocaOOB() {414; CHECK-LABEL: @ArrayAllocaOOB dso_preemptable{{$}}415; CHECK-NEXT: args uses:416; CHECK-NEXT: allocas uses:417; CHECK-NEXT: x[40]: [37,41){{$}}418; GLOBAL-NEXT: safe accesses:419; CHECK-EMPTY:420entry:421 %x = alloca i32, i32 10, align 4422 %x2 = getelementptr i8, ptr %x, i64 37423 store i32 0, ptr %x2, align 1424 ret void425}426 427define void @DynamicAllocaUnused(i64 %size) {428; CHECK-LABEL: @DynamicAllocaUnused dso_preemptable{{$}}429; CHECK-NEXT: args uses:430; CHECK-NEXT: allocas uses:431; CHECK-NEXT: x[0]: empty-set{{$}}432; GLOBAL-NEXT: safe accesses:433; CHECK-EMPTY:434entry:435 %x = alloca i32, i64 %size, align 16436 ret void437}438 439; Dynamic alloca with unknown size.440define void @DynamicAlloca(i64 %size) {441; CHECK-LABEL: @DynamicAlloca dso_preemptable{{$}}442; CHECK-NEXT: args uses:443; CHECK-NEXT: allocas uses:444; CHECK-NEXT: x[0]: [0,4){{$}}445; GLOBAL-NEXT: safe accesses:446; CHECK-EMPTY:447entry:448 %x = alloca i32, i64 %size, align 16449 store i32 0, ptr %x, align 1450 ret void451}452 453; Dynamic alloca with limited size.454; FIXME: could be proved safe. Implement.455define void @DynamicAllocaFiniteSizeRange(i1 zeroext %z) {456; CHECK-LABEL: @DynamicAllocaFiniteSizeRange dso_preemptable{{$}}457; CHECK-NEXT: args uses:458; CHECK-NEXT: allocas uses:459; CHECK-NEXT: x[0]: [0,4){{$}}460; GLOBAL-NEXT: safe accesses:461; CHECK-EMPTY:462entry:463 %size = select i1 %z, i64 3, i64 5464 %x = alloca i32, i64 %size, align 16465 store i32 0, ptr %x, align 1466 ret void467}468 469define signext i8 @SimpleLoop() {470; CHECK-LABEL: @SimpleLoop dso_preemptable{{$}}471; CHECK-NEXT: args uses:472; CHECK-NEXT: allocas uses:473; CHECK-NEXT: x[10]: [0,10){{$}}474; GLOBAL-NEXT: safe accesses:475; GLOBAL-NEXT: %load = load volatile i8, ptr %p.09, align 1476; CHECK-EMPTY:477entry:478 %x = alloca [10 x i8], align 1479 %lftr.limit = getelementptr inbounds [10 x i8], ptr %x, i64 0, i64 10480 br label %for.body481 482for.body:483 %sum.010 = phi i8 [ 0, %entry ], [ %add, %for.body ]484 %p.09 = phi ptr [ %x, %entry ], [ %incdec.ptr, %for.body ]485 %incdec.ptr = getelementptr inbounds i8, ptr %p.09, i64 1486 %load = load volatile i8, ptr %p.09, align 1487 %add = add i8 %load, %sum.010488 %exitcond = icmp eq ptr %incdec.ptr, %lftr.limit489 br i1 %exitcond, label %for.cond.cleanup, label %for.body490 491for.cond.cleanup:492 ret i8 %add493}494 495; OOB in a loop.496define signext i8 @SimpleLoopOOB() {497; CHECK-LABEL: @SimpleLoopOOB dso_preemptable{{$}}498; CHECK-NEXT: args uses:499; CHECK-NEXT: allocas uses:500; CHECK-NEXT: x[10]: [0,11){{$}}501; GLOBAL-NEXT: safe accesses:502; CHECK-EMPTY:503entry:504 %x = alloca [10 x i8], align 1505 ; 11 iterations506 %lftr.limit = getelementptr inbounds [10 x i8], ptr %x, i64 0, i64 11507 br label %for.body508 509for.body:510 %sum.010 = phi i8 [ 0, %entry ], [ %add, %for.body ]511 %p.09 = phi ptr [ %x, %entry ], [ %incdec.ptr, %for.body ]512 %incdec.ptr = getelementptr inbounds i8, ptr %p.09, i64 1513 %load = load volatile i8, ptr %p.09, align 1514 %add = add i8 %load, %sum.010515 %exitcond = icmp eq ptr %incdec.ptr, %lftr.limit516 br i1 %exitcond, label %for.cond.cleanup, label %for.body517 518for.cond.cleanup:519 ret i8 %add520}521 522define dso_local void @SizeCheck(i32 %sz) {523; CHECK-LABEL: @SizeCheck{{$}}524; CHECK-NEXT: args uses:525; CHECK-NEXT: allocas uses:526; CHECK-NEXT: x1[128]: [0,4294967295){{$}}527; GLOBAL-NEXT: safe accesses:528; CHECK-EMPTY:529entry:530 %x1 = alloca [128 x i8], align 16531 %cmp = icmp slt i32 %sz, 129532 br i1 %cmp, label %if.then, label %if.end533 534if.then:535 call void @llvm.memset.p0.i32(ptr nonnull align 16 %x1, i8 0, i32 %sz, i1 false)536 br label %if.end537 538if.end:539 ret void540}541 542; FIXME: scalable allocas are considered to be of size zero, and scalable accesses to be full-range.543; This effectively disables safety analysis for scalable allocations.544define void @Scalable(ptr %p, ptr %unused, <vscale x 4 x i32> %v) {545; CHECK-LABEL: @Scalable dso_preemptable{{$}}546; CHECK-NEXT: args uses:547; CHECK-NEXT: p[]: full-set548; CHECK-NEXT: unused[]: empty-set549; CHECK-NEXT: allocas uses:550; CHECK-NEXT: x[0]: [0,1){{$}}551; GLOBAL-NEXT: safe accesses:552; GLOBAL-NEXT: store <vscale x 4 x i32> %v, ptr %p, align 4553; CHECK-EMPTY:554entry:555 %x = alloca <vscale x 4 x i32>, align 4556 store i8 0, ptr %x, align 1557 store <vscale x 4 x i32> %v, ptr %p, align 4558 ret void559}560 561%zerosize_type = type {}562 563define void @ZeroSize(ptr %p) {564; CHECK-LABEL: @ZeroSize dso_preemptable{{$}}565; CHECK-NEXT: args uses:566; CHECK-NEXT: p[]: empty-set567; CHECK-NEXT: allocas uses:568; CHECK-NEXT: x[0]: empty-set569; GLOBAL-NEXT: safe accesses:570; GLOBAL-NEXT: store %zerosize_type undef, ptr %x, align 4571; GLOBAL-NEXT: store %zerosize_type undef, ptr undef, align 4572; GLOBAL-NEXT: load %zerosize_type, ptr %p, align573; CHECK-EMPTY:574entry:575 %x = alloca %zerosize_type, align 4576 store %zerosize_type undef, ptr %x, align 4577 store %zerosize_type undef, ptr undef, align 4578 %val = load %zerosize_type, ptr %p, align 4579 ret void580}581 582define void @OperandBundle() {583; CHECK-LABEL: @OperandBundle dso_preemptable{{$}}584; CHECK-NEXT: args uses:585; CHECK-NEXT: allocas uses:586; CHECK-NEXT: a[4]: full-set587; GLOBAL-NEXT: safe accesses:588; CHECK-EMPTY:589entry:590 %a = alloca i32, align 4591 call void @LeakAddress() ["unknown"(ptr %a)]592 ret void593}594 595define void @ByVal(ptr byval(i16) %p) {596 ; CHECK-LABEL: @ByVal dso_preemptable{{$}}597 ; CHECK-NEXT: args uses:598 ; CHECK-NEXT: allocas uses:599 ; GLOBAL-NEXT: safe accesses:600 ; CHECK-EMPTY:601entry:602 ret void603}604 605define void @TestByVal() {606; CHECK-LABEL: @TestByVal dso_preemptable{{$}}607; CHECK-NEXT: args uses:608; CHECK-NEXT: allocas uses:609; CHECK-NEXT: x[2]: [0,2)610; CHECK-NEXT: y[8]: [0,2)611; GLOBAL-NEXT: safe accesses:612; GLOBAL-NEXT: call void @ByVal(ptr byval(i16) %x)613; GLOBAL-NEXT: call void @ByVal(ptr byval(i16) %y)614; CHECK-EMPTY:615entry:616 %x = alloca i16, align 4617 call void @ByVal(ptr byval(i16) %x)618 619 %y = alloca i64, align 4620 call void @ByVal(ptr byval(i16) %y)621 622 ret void623}624 625declare void @ByValArray(ptr byval([100000 x i64]) %p)626 627define void @TestByValArray() {628; CHECK-LABEL: @TestByValArray dso_preemptable{{$}}629; CHECK-NEXT: args uses:630; CHECK-NEXT: allocas uses:631; CHECK-NEXT: z[800000]: [500000,1300000)632; GLOBAL-NEXT: safe accesses:633; CHECK-EMPTY:634entry:635 %z = alloca [100000 x i64], align 4636 %z2 = getelementptr i8, ptr %z, i64 500000637 call void @ByValArray(ptr byval([100000 x i64]) %z2)638 ret void639}640 641define dso_local i8 @LoadMinInt64(ptr %p) {642 ; CHECK-LABEL: @LoadMinInt64{{$}}643 ; CHECK-NEXT: args uses:644 ; CHECK-NEXT: p[]: [-9223372036854775808,-9223372036854775807){{$}}645 ; CHECK-NEXT: allocas uses:646 ; GLOBAL-NEXT: safe accesses:647 ; GLOBAL-NEXT: load i8, ptr %p2, align 1648 ; CHECK-EMPTY:649 %p2 = getelementptr i8, ptr %p, i64 -9223372036854775808650 %v = load i8, ptr %p2, align 1651 ret i8 %v652}653 654define void @Overflow() {655; CHECK-LABEL: @Overflow dso_preemptable{{$}}656; CHECK-NEXT: args uses:657; CHECK-NEXT: allocas uses:658; LOCAL-NEXT: x[1]: empty-set, @LoadMinInt64(arg0, [-9223372036854775808,-9223372036854775807)){{$}}659; GLOBAL-NEXT: x[1]: full-set, @LoadMinInt64(arg0, [-9223372036854775808,-9223372036854775807)){{$}}660; GLOBAL-NEXT: safe accesses:661; CHECK-EMPTY:662entry:663 %x = alloca i8, align 4664 %x2 = getelementptr i8, ptr %x, i64 -9223372036854775808665 %v = call i8 @LoadMinInt64(ptr %x2)666 ret void667}668 669define void @DeadBlock(ptr %p) {670; CHECK-LABEL: @DeadBlock dso_preemptable{{$}}671; CHECK-NEXT: args uses:672; CHECK-NEXT: p[]: empty-set{{$}}673; CHECK-NEXT: allocas uses:674; CHECK-NEXT: x[1]: empty-set{{$}}675; GLOBAL-NEXT: safe accesses:676; GLOBAL-NEXT: store i8 5, ptr %x677; GLOBAL-NEXT: store i64 -5, ptr %p678; CHECK-EMPTY:679entry:680 %x = alloca i8, align 4681 br label %end682 683dead:684 store i8 5, ptr %x685 store i64 -5, ptr %p686 br label %end687 688end:689 ret void690}691 692define void @LifeNotStarted() {693; CHECK-LABEL: @LifeNotStarted dso_preemptable{{$}}694; CHECK-NEXT: args uses:695; CHECK-NEXT: allocas uses:696; CHECK: x[1]: full-set{{$}}697; CHECK: y[1]: full-set{{$}}698; CHECK: z[1]: full-set{{$}}699; GLOBAL-NEXT: safe accesses:700; CHECK-EMPTY:701entry:702 %x = alloca i8, align 4703 %y = alloca i8, align 4704 %z = alloca i8, align 4705 706 store i8 5, ptr %x707 %n = load i8, ptr %y708 call void @llvm.memset.p0.i32(ptr nonnull %z, i8 0, i32 1, i1 false)709 710 call void @llvm.lifetime.start.p0(ptr %x)711 call void @llvm.lifetime.start.p0(ptr %y)712 call void @llvm.lifetime.start.p0(ptr %z)713 714 ret void715}716 717define void @LifeOK() {718; CHECK-LABEL: @LifeOK dso_preemptable{{$}}719; CHECK-NEXT: args uses:720; CHECK-NEXT: allocas uses:721; CHECK: x[1]: [0,1){{$}}722; CHECK: y[1]: [0,1){{$}}723; CHECK: z[1]: [0,1){{$}}724; GLOBAL-NEXT: safe accesses:725; GLOBAL-NEXT: store i8 5, ptr %x726; GLOBAL-NEXT: %n = load i8, ptr %y727; GLOBAL-NEXT: call void @llvm.memset.p0.i32(ptr nonnull %z, i8 0, i32 1, i1 false)728; CHECK-EMPTY:729entry:730 %x = alloca i8, align 4731 %y = alloca i8, align 4732 %z = alloca i8, align 4733 734 call void @llvm.lifetime.start.p0(ptr %x)735 call void @llvm.lifetime.start.p0(ptr %y)736 call void @llvm.lifetime.start.p0(ptr %z)737 738 store i8 5, ptr %x739 %n = load i8, ptr %y740 call void @llvm.memset.p0.i32(ptr nonnull %z, i8 0, i32 1, i1 false)741 742 ret void743}744 745define void @LifeEnded() {746; CHECK-LABEL: @LifeEnded dso_preemptable{{$}}747; CHECK-NEXT: args uses:748; CHECK-NEXT: allocas uses:749; CHECK: x[1]: full-set{{$}}750; CHECK: y[1]: full-set{{$}}751; CHECK: z[1]: full-set{{$}}752; GLOBAL-NEXT: safe accesses:753; CHECK-EMPTY:754entry:755 %x = alloca i8, align 4756 %y = alloca i8, align 4757 %z = alloca i8, align 4758 759 call void @llvm.lifetime.start.p0(ptr %x)760 call void @llvm.lifetime.start.p0(ptr %y)761 call void @llvm.lifetime.start.p0(ptr %z)762 763 call void @llvm.lifetime.end.p0(ptr %x)764 call void @llvm.lifetime.end.p0(ptr %y)765 call void @llvm.lifetime.end.p0(ptr %z)766 767 store i8 5, ptr %x768 %n = load i8, ptr %y769 call void @llvm.memset.p0.i32(ptr nonnull %z, i8 0, i32 1, i1 false)770 771 ret void772}773 774define void @TwoAllocasOK() {775; CHECK-LABEL: @TwoAllocasOK776; CHECK-NEXT: args uses:777; CHECK-NEXT: allocas uses:778; CHECK: a[4]: [0,1){{$}}779; CHECK: y[1]: [0,1){{$}}780; GLOBAL-NEXT: safe accesses:781; GLOBAL-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr %y, ptr %a, i32 1, i1 false)782; CHECK-EMPTY:783entry:784 %a = alloca i32, align 4785 %y = alloca i8, align 4786 call void @llvm.memcpy.p0.p0.i32(ptr %y, ptr %a, i32 1, i1 false)787 ret void788}789 790define void @TwoAllocasOOBDest() {791; CHECK-LABEL: @TwoAllocasOOBDest792; CHECK-NEXT: args uses:793; CHECK-NEXT: allocas uses:794; CHECK: a[4]: [0,4){{$}}795; CHECK: y[1]: [0,4){{$}}796; GLOBAL-NEXT: safe accesses:797; CHECK-EMPTY:798entry:799 %a = alloca i32, align 4800 %y = alloca i8, align 4801 call void @llvm.memcpy.p0.p0.i32(ptr %y, ptr %a, i32 4, i1 false)802 ret void803}804 805define void @TwoAllocasOOBSource() {806; CHECK-LABEL: @TwoAllocasOOBSource807; CHECK-NEXT: args uses:808; CHECK-NEXT: allocas uses:809; CHECK: a[4]: [0,4){{$}}810; CHECK: y[1]: [0,4){{$}}811; GLOBAL-NEXT: safe accesses:812; CHECK-EMPTY:813entry:814 %a = alloca i32, align 4815 %y = alloca i8, align 4816 call void @llvm.memcpy.p0.p0.i32(ptr %a, ptr %y, i32 4, i1 false)817 ret void818}819 820define void @TwoAllocasOOBBoth() {821; CHECK-LABEL: @TwoAllocasOOBBoth822; CHECK-NEXT: args uses:823; CHECK-NEXT: allocas uses:824; CHECK: a[4]: [0,5){{$}}825; CHECK: y[1]: [0,5){{$}}826; GLOBAL-NEXT: safe accesses:827; CHECK-EMPTY:828entry:829 %a = alloca i32, align 4830 %y = alloca i8, align 4831 call void @llvm.memcpy.p0.p0.i32(ptr %y, ptr %a, i32 5, i1 false)832 ret void833}834 835define void @MixedAccesses() {836; CHECK-LABEL: @MixedAccesses837; CHECK-NEXT: args uses:838; CHECK-NEXT: allocas uses:839; CHECK: a[4]: [0,5){{$}}840; GLOBAL-NEXT: safe accesses:841; GLOBAL-NEXT: call void @llvm.memset.p0.i32(ptr %a, i8 1, i32 4, i1 false)842; CHECK-EMPTY:843entry:844 %a = alloca i32, align 4845 call void @llvm.memset.p0.i32(ptr %a, i8 1, i32 5, i1 false)846 call void @llvm.memset.p0.i32(ptr %a, i8 1, i32 4, i1 false)847 ret void848}849 850define void @MixedAccesses2() {851; CHECK-LABEL: @MixedAccesses2852; CHECK-NEXT: args uses:853; CHECK-NEXT: allocas uses:854; CHECK: a[4]: [0,8){{$}}855; GLOBAL-NEXT: safe accesses:856; GLOBAL-NEXT: load i32, ptr %a, align 4857; CHECK-EMPTY:858entry:859 %a = alloca i32, align 4860 %n1 = load i64, ptr %a, align 4861 %n2 = load i32, ptr %a, align 4862 ret void863}864 865define void @MixedAccesses3(ptr %func) {866; CHECK-LABEL: @MixedAccesses3867; CHECK-NEXT: args uses:868; CHECK-NEXT: func[]: full-set869; CHECK-NEXT: allocas uses:870; CHECK: a[4]: full-set{{$}}871; GLOBAL-NEXT: safe accesses:872; GLOBAL-NEXT: load i32, ptr %a, align 4873; CHECK-EMPTY:874entry:875 %a = alloca i32, align 4876 %n2 = load i32, ptr %a, align 4877 call void %func(ptr %a)878 ret void879}880 881define void @MixedAccesses4() {882; CHECK-LABEL: @MixedAccesses4883; CHECK-NEXT: args uses:884; CHECK-NEXT: allocas uses:885; CHECK: a[4]: full-set{{$}}886; CHECK: a1[8]: [0,8){{$}}887; GLOBAL-NEXT: safe accesses:888; GLOBAL-NEXT: load i32, ptr %a, align 4889; CHECK-EMPTY:890entry:891 %a = alloca i32, align 4892 %a1 = alloca ptr, align 4893 %n2 = load i32, ptr %a, align 4894 store ptr %a, ptr %a1895 ret void896}897 898define ptr @MixedAccesses5(i1 %x, ptr %y) {899; CHECK-LABEL: @MixedAccesses5900; CHECK-NEXT: args uses:901; CHECK: y[]: full-set902; CHECK-NEXT: allocas uses:903; CHECK: a[4]: full-set{{$}}904; GLOBAL-NEXT: safe accesses:905; GLOBAL-NEXT: load i32, ptr %a, align 4906; CHECK-EMPTY:907entry:908 %a = alloca i32, align 4909 br i1 %x, label %tlabel, label %flabel910flabel:911 %n = load i32, ptr %a, align 4912 ret ptr %y913tlabel:914 ret ptr %a915}916 917define void @MixedAccesses6(ptr %arg) {918; CHECK-LABEL: @MixedAccesses6919; CHECK-NEXT: args uses:920; CHECK-NEXT: arg[]: [0,4)921; CHECK-NEXT: allocas uses:922; CHECK: a[4]: [0,4)923; GLOBAL-NEXT: safe accesses:924; GLOBAL-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr %a, ptr %arg, i32 4, i1 false)925; CHECK-EMPTY:926entry:927 %a = alloca i32, align 4928 call void @llvm.memcpy.p0.p0.i32(ptr %a, ptr %arg, i32 4, i1 false)929 ret void930}931 932define void @MixedAccesses7(i1 %cond, ptr %arg) {933; SECV doesn't support select, so we consider this non-stack-safe, even through934; it is.935;936; CHECK-LABEL: @MixedAccesses7937; CHECK-NEXT: args uses:938; CHECK-NEXT: arg[]: full-set939; CHECK-NEXT: allocas uses:940; CHECK: a[4]: full-set941; GLOBAL-NEXT: safe accesses:942; CHECK-EMPTY:943entry:944 %a = alloca i32, align 4945 %x1 = select i1 %cond, ptr %arg, ptr %a946 call void @llvm.memcpy.p0.p0.i32(ptr %x1, ptr %arg, i32 4, i1 false)947 ret void948}949 950define void @NoStackAccess(ptr %arg1, ptr %arg2) {951; CHECK-LABEL: @NoStackAccess952; CHECK-NEXT: args uses:953; CHECK-NEXT: arg1[]: [0,4)954; CHECK-NEXT: arg2[]: [0,4)955; CHECK-NEXT: allocas uses:956; CHECK: a[4]: empty-set{{$}}957; GLOBAL-NEXT: safe accesses:958; GLOBAL-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr %arg1, ptr %arg2, i32 4, i1 false)959; CHECK-EMPTY:960entry:961 %a = alloca i32, align 4962 call void @llvm.memcpy.p0.p0.i32(ptr %arg1, ptr %arg2, i32 4, i1 false)963 ret void964}965 966define void @DoubleLifetime() {967; CHECK-LABEL: @DoubleLifetime968; CHECK-NEXT: args uses:969; CHECK-NEXT: allocas uses:970; CHECK: a[4]: full-set{{$}}971; GLOBAL-NEXT: safe accesses:972; GLOBAL-NEXT: call void @llvm.memset.p0.i32(ptr %a, i8 1, i32 4, i1 false)973; CHECK-EMPTY:974entry:975 %a = alloca i32, align 4976 call void @llvm.lifetime.start.p0(ptr %a)977 call void @llvm.lifetime.end.p0(ptr %a)978 call void @llvm.memset.p0.i32(ptr %a, i8 1, i32 4, i1 true)979 980 call void @llvm.lifetime.start.p0(ptr %a)981 call void @llvm.memset.p0.i32(ptr %a, i8 1, i32 4, i1 false)982 call void @llvm.lifetime.end.p0(ptr %a)983 ret void984}985 986define void @DoubleLifetime2() {987; CHECK-LABEL: @DoubleLifetime2988; CHECK-NEXT: args uses:989; CHECK-NEXT: allocas uses:990; CHECK: a[4]: full-set{{$}}991; GLOBAL-NEXT: safe accesses:992; GLOBAL-NEXT: call void @llvm.memset.p0.i32(ptr %a, i8 1, i32 4, i1 false)993; CHECK-EMPTY:994entry:995 %a = alloca i32, align 4996 call void @llvm.lifetime.start.p0(ptr %a)997 call void @llvm.lifetime.end.p0(ptr %a)998 %n = load i32, ptr %a999 1000 call void @llvm.lifetime.start.p0(ptr %a)1001 call void @llvm.memset.p0.i32(ptr %a, i8 1, i32 4, i1 false)1002 call void @llvm.lifetime.end.p0(ptr %a)1003 ret void1004}1005 1006define void @DoubleLifetime3() {1007; CHECK-LABEL: @DoubleLifetime31008; CHECK-NEXT: args uses:1009; CHECK-NEXT: allocas uses:1010; CHECK: a[4]: full-set{{$}}1011; GLOBAL-NEXT: safe accesses:1012; GLOBAL-NEXT: call void @llvm.memset.p0.i32(ptr %a, i8 1, i32 4, i1 false)1013; CHECK-EMPTY:1014entry:1015 %a = alloca i32, align 41016 call void @llvm.lifetime.start.p0(ptr %a)1017 call void @llvm.lifetime.end.p0(ptr %a)1018 store i32 5, ptr %a1019 1020 call void @llvm.lifetime.start.p0(ptr %a)1021 call void @llvm.memset.p0.i32(ptr %a, i8 1, i32 4, i1 false)1022 call void @llvm.lifetime.end.p0(ptr %a)1023 ret void1024}1025 1026define void @DoubleLifetime4() {1027; CHECK-LABEL: @DoubleLifetime41028; CHECK-NEXT: args uses:1029; CHECK-NEXT: allocas uses:1030; CHECK: a[4]: full-set{{$}}1031; GLOBAL-NEXT: safe accesses:1032; GLOBAL-NEXT: call void @llvm.memset.p0.i32(ptr %a, i8 1, i32 4, i1 false)1033; CHECK-EMPTY:1034entry:1035 %a = alloca i32, align 41036 call void @llvm.lifetime.start.p0(ptr %a)1037 call void @llvm.memset.p0.i32(ptr %a, i8 1, i32 4, i1 false)1038 call void @llvm.lifetime.end.p0(ptr %a)1039 call void @unknown_call(ptr %a)1040 ret void1041}1042 1043define void @Cmpxchg4Arg(ptr %p) {1044; CHECK-LABEL: @Cmpxchg4Arg1045; CHECK-NEXT: args uses:1046; CHECK-NEXT: p[]: [0,4){{$}}1047; CHECK-NEXT: allocas uses:1048; GLOBAL-NEXT: safe accesses:1049; GLOBAL-NEXT: cmpxchg ptr %p, i32 0, i32 1 monotonic monotonic, align 11050; CHECK-EMPTY:1051entry:1052 cmpxchg ptr %p, i32 0, i32 1 monotonic monotonic, align 11053 ret void1054}1055 1056define void @AtomicRMW4Arg(ptr %p) {1057; CHECK-LABEL: @AtomicRMW4Arg1058; CHECK-NEXT: args uses:1059; CHECK-NEXT: p[]: [0,4){{$}}1060; CHECK-NEXT: allocas uses:1061; GLOBAL-NEXT: safe accesses:1062; GLOBAL-NEXT: atomicrmw add ptr %p, i32 1 monotonic, align 11063; CHECK-EMPTY:1064entry:1065 atomicrmw add ptr %p, i32 1 monotonic, align 11066 ret void1067}1068 1069define void @Cmpxchg4Alloca() {1070; CHECK-LABEL: @Cmpxchg4Alloca1071; CHECK-NEXT: args uses:1072; CHECK-NEXT: allocas uses:1073; CHECK-NEXT: x[4]: [0,4){{$}}1074; GLOBAL-NEXT: safe accesses:1075; GLOBAL-NEXT: cmpxchg ptr %x, i32 0, i32 1 monotonic monotonic, align 11076; CHECK-EMPTY:1077entry:1078 %x = alloca i32, align 41079 cmpxchg ptr %x, i32 0, i32 1 monotonic monotonic, align 11080 ret void1081}1082 1083define void @AtomicRMW4Alloca() {1084; CHECK-LABEL: @AtomicRMW4Alloca1085; CHECK-NEXT: args uses:1086; CHECK-NEXT: allocas uses:1087; CHECK-NEXT: x[4]: [0,4){{$}}1088; GLOBAL-NEXT: safe accesses:1089; GLOBAL-NEXT: atomicrmw add ptr %x, i32 1 monotonic, align 11090; CHECK-EMPTY:1091entry:1092 %x = alloca i32, align 41093 atomicrmw add ptr %x, i32 1 monotonic, align 11094 ret void1095}1096 1097define void @StoreArg(ptr %p) {1098; CHECK-LABEL: @StoreArg1099; CHECK-NEXT: args uses:1100; CHECK-NEXT: p[]: [0,4){{$}}1101; CHECK-NEXT: allocas uses:1102; GLOBAL-NEXT: safe accesses:1103; GLOBAL-NEXT: store i32 1, ptr %p1104; CHECK-EMPTY:1105entry:1106 store i32 1, ptr %p1107 ret void1108}1109 1110define void @NonPointer(ptr %p) {1111; CHECK-LABEL: @NonPointer1112; CHECK-NEXT: args uses:1113; LOCAL-NEXT: p[]: empty-set, @unknown_call_int(arg0, full-set)1114; GLOBAL-NEXT: p[]: full-set, @unknown_call_int(arg0, full-set)1115; CHECK-NEXT: allocas uses:1116; GLOBAL-NEXT: safe accesses:1117; CHECK-EMPTY:1118 %int = ptrtoint ptr %p to i641119 call void @unknown_call_int(i64 %int)1120 ret void1121}1122 1123@ifunc = dso_local ifunc i64 (ptr), ptr @ifunc_resolver1124 1125define dso_local void @CallIfunc(ptr noundef %uaddr) local_unnamed_addr {1126; CHECK-LABEL: @CallIfunc1127; CHECK-NEXT: args uses:1128; CHECK-NEXT: uaddr[]: full-set1129entry:1130 tail call i64 @ifunc(ptr noundef %uaddr)1131 ret void1132}1133 1134define dso_local ptr @ifunc_resolver() {1135entry:1136 ret ptr null1137}1138 1139declare void @llvm.lifetime.start.p0(ptr nocapture)1140declare void @llvm.lifetime.end.p0(ptr nocapture)1141