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 3 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 8 8 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 4 28 store ptr %x, ptr @sink, align 8 29 ret void 30} 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 1 39; CHECK-EMPTY: 40entry: 41 %x = alloca i32, align 4 42 store i8 0, ptr %x, align 1 43 ret void 44} 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 1 53; CHECK-EMPTY: 54entry: 55 %x = alloca i32, align 4 56 %c1 = icmp sge i64 %i, 0 57 %c2 = icmp slt i64 %i, 4 58 br i1 %c1, label %c1.true, label %false 59 60c1.true: 61 br i1 %c2, label %c2.true, label %false 62 63c2.true: 64 %x2 = getelementptr i8, ptr %x, i64 %i 65 store i8 0, ptr %x2, align 1 66 br label %false 67 68false: 69 ret void 70} 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 1 79; CHECK-EMPTY: 80entry: 81 %x = alloca i32, align 4 82 %c1 = icmp sge i64 %i, 0 83 %i1 = select i1 %c1, i64 %i, i64 0 84 %c2 = icmp slt i64 %i1, 3 85 %i2 = select i1 %c2, i64 %i1, i64 3 86 %x2 = getelementptr i8, ptr %x, i64 %i2 87 store i8 0, ptr %x2, align 1 88 ret void 89} 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 4 98; CHECK-EMPTY: 99entry: 100 %x = alloca i32, align 4 101 store i32 0, ptr %x, align 4 102 ret void 103} 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 1 112; CHECK-EMPTY: 113entry: 114 %x = alloca i32, align 4 115 %x2 = getelementptr i8, ptr %x, i64 2 116 store i8 0, ptr %x2, align 1 117 ret void 118} 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 4 130 %x1 = ptrtoint ptr %x to i64 131 %x2 = add i64 %x1, 2 132 %x3 = inttoptr i64 %x2 to ptr 133 store i8 0, ptr %x3, align 1 134 ret void 135} 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 1 145; CHECK-EMPTY: 146entry: 147 %x = alloca i32, align 4 148 %x2 = call ptr @retptr(ptr %x) 149 store i8 0, ptr %x2, align 1 150 ret void 151} 152 153define dso_local void @WriteMinMax(ptr %p) { 154; CHECK-LABEL: @WriteMinMax{{$}} 155; CHECK-NEXT: args uses: 156; CHECK-NEXT: p[]: full-set 157; CHECK-NEXT: allocas uses: 158; GLOBAL-NEXT: safe accesses: 159; GLOBAL-NEXT: store i8 0, ptr %p1, align 1 160; GLOBAL-NEXT: store i8 0, ptr %p2, align 1 161; CHECK-EMPTY: 162entry: 163 %p1 = getelementptr i8, ptr %p, i64 9223372036854775805 164 store i8 0, ptr %p1, align 1 165 %p2 = getelementptr i8, ptr %p, i64 -9223372036854775805 166 store i8 0, ptr %p2, align 1 167 ret void 168} 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 -9223372036854775807 182 call void @llvm.memset.p0.i64(ptr %p2, i8 1, i64 9223372036854775806, i1 0) 183 ret void 184} 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 4 195 %x2 = getelementptr i8, ptr %x, i64 2 196 store i32 0, ptr %x2, align 1 197 ret void 198} 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 4 209 %c1 = icmp sge i64 %i, 0 210 %c2 = icmp slt i64 %i, 5 211 br i1 %c1, label %c1.true, label %false 212 213c1.true: 214 br i1 %c2, label %c2.true, label %false 215 216c2.true: 217 %x2 = getelementptr i8, ptr %x, i64 %i 218 store i8 0, ptr %x2, align 1 219 br label %false 220 221false: 222 ret void 223} 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 4 234 %c2 = icmp slt i64 %i, 5 235 br i1 %c2, label %c2.true, label %false 236 237c2.true: 238 %x2 = getelementptr i8, ptr %x, i64 %i 239 store i8 0, ptr %x2, align 1 240 br label %false 241 242false: 243 ret void 244} 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 4 256 %x2 = getelementptr i8, ptr %x, i64 2 257 %x3 = call ptr @retptr(ptr %x2) 258 store i32 0, ptr %x3, align 1 259 ret void 260} 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 1 270; CHECK-EMPTY: 271entry: 272 %x = alloca i32, align 4 273 %v = load i8, ptr %x, align 1 274 ret void 275} 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 4 286 %x2 = getelementptr i8, ptr %x, i64 2 287 %v = load i32, ptr %x2, align 1 288 ret void 289} 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 4 301 %x2 = getelementptr i8, ptr %x, i64 2 302 ret ptr %x2 303} 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 4 317 %x2 = getelementptr i16, ptr %x, i64 1 318 call void @Foo(ptr %x2); 319 ret void 320} 321 322; Indirect calls can not be analyzed (yet). 323; FIXME: %p[]: full-set looks invalid 324define 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 4 334 call void %p(ptr %x); 335 ret void 336} 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 1 346; CHECK-EMPTY: 347entry: 348 %x = alloca i32, align 4 349 %idx = select i1 %z, i64 1, i64 2 350 %x2 = getelementptr i8, ptr %x, i64 %idx 351 store i8 0, ptr %x2, align 1 352 ret void 353} 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 4 364 %x2 = getelementptr i32, ptr %x, i64 -400000000000 365 store i32 0, ptr %x2, align 1 366 ret void 367} 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 4 378 %x2 = getelementptr i32, ptr %x, i16 %z 379 store i32 0, ptr %x2, align 1 380 ret void 381} 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 4 392 %idx = select i1 %z, i64 1, i64 4 393 %x2 = getelementptr i8, ptr %x, i64 %idx 394 store i8 0, ptr %x2, align 1 395 ret void 396} 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 1 405; CHECK-EMPTY: 406entry: 407 %x = alloca i32, i32 10, align 4 408 %x2 = getelementptr i8, ptr %x, i64 36 409 store i32 0, ptr %x2, align 1 410 ret void 411} 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 4 422 %x2 = getelementptr i8, ptr %x, i64 37 423 store i32 0, ptr %x2, align 1 424 ret void 425} 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 16 436 ret void 437} 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 16 449 store i32 0, ptr %x, align 1 450 ret void 451} 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 5 464 %x = alloca i32, i64 %size, align 16 465 store i32 0, ptr %x, align 1 466 ret void 467} 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 1 476; CHECK-EMPTY: 477entry: 478 %x = alloca [10 x i8], align 1 479 %lftr.limit = getelementptr inbounds [10 x i8], ptr %x, i64 0, i64 10 480 br label %for.body 481 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 1 486 %load = load volatile i8, ptr %p.09, align 1 487 %add = add i8 %load, %sum.010 488 %exitcond = icmp eq ptr %incdec.ptr, %lftr.limit 489 br i1 %exitcond, label %for.cond.cleanup, label %for.body 490 491for.cond.cleanup: 492 ret i8 %add 493} 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 1 505 ; 11 iterations 506 %lftr.limit = getelementptr inbounds [10 x i8], ptr %x, i64 0, i64 11 507 br label %for.body 508 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 1 513 %load = load volatile i8, ptr %p.09, align 1 514 %add = add i8 %load, %sum.010 515 %exitcond = icmp eq ptr %incdec.ptr, %lftr.limit 516 br i1 %exitcond, label %for.cond.cleanup, label %for.body 517 518for.cond.cleanup: 519 ret i8 %add 520} 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 16 531 %cmp = icmp slt i32 %sz, 129 532 br i1 %cmp, label %if.then, label %if.end 533 534if.then: 535 call void @llvm.memset.p0.i32(ptr nonnull align 16 %x1, i8 0, i32 %sz, i1 false) 536 br label %if.end 537 538if.end: 539 ret void 540} 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-set 548; CHECK-NEXT: unused[]: empty-set 549; 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 4 553; CHECK-EMPTY: 554entry: 555 %x = alloca <vscale x 4 x i32>, align 4 556 store i8 0, ptr %x, align 1 557 store <vscale x 4 x i32> %v, ptr %p, align 4 558 ret void 559} 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-set 567; CHECK-NEXT: allocas uses: 568; CHECK-NEXT: x[0]: empty-set 569; GLOBAL-NEXT: safe accesses: 570; GLOBAL-NEXT: store %zerosize_type undef, ptr %x, align 4 571; GLOBAL-NEXT: store %zerosize_type undef, ptr undef, align 4 572; GLOBAL-NEXT: load %zerosize_type, ptr %p, align 573; CHECK-EMPTY: 574entry: 575 %x = alloca %zerosize_type, align 4 576 store %zerosize_type undef, ptr %x, align 4 577 store %zerosize_type undef, ptr undef, align 4 578 %val = load %zerosize_type, ptr %p, align 4 579 ret void 580} 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-set 587; GLOBAL-NEXT: safe accesses: 588; CHECK-EMPTY: 589entry: 590 %a = alloca i32, align 4 591 call void @LeakAddress() ["unknown"(ptr %a)] 592 ret void 593} 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 void 603} 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 4 617 call void @ByVal(ptr byval(i16) %x) 618 619 %y = alloca i64, align 4 620 call void @ByVal(ptr byval(i16) %y) 621 622 ret void 623} 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 4 636 %z2 = getelementptr i8, ptr %z, i64 500000 637 call void @ByValArray(ptr byval([100000 x i64]) %z2) 638 ret void 639} 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 1 648 ; CHECK-EMPTY: 649 %p2 = getelementptr i8, ptr %p, i64 -9223372036854775808 650 %v = load i8, ptr %p2, align 1 651 ret i8 %v 652} 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 4 664 %x2 = getelementptr i8, ptr %x, i64 -9223372036854775808 665 %v = call i8 @LoadMinInt64(ptr %x2) 666 ret void 667} 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 %x 677; GLOBAL-NEXT: store i64 -5, ptr %p 678; CHECK-EMPTY: 679entry: 680 %x = alloca i8, align 4 681 br label %end 682 683dead: 684 store i8 5, ptr %x 685 store i64 -5, ptr %p 686 br label %end 687 688end: 689 ret void 690} 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 4 703 %y = alloca i8, align 4 704 %z = alloca i8, align 4 705 706 store i8 5, ptr %x 707 %n = load i8, ptr %y 708 call void @llvm.memset.p0.i32(ptr nonnull %z, i8 0, i32 1, i1 false) 709 710 call void @llvm.lifetime.start.p0(i64 1, ptr %x) 711 call void @llvm.lifetime.start.p0(i64 1, ptr %y) 712 call void @llvm.lifetime.start.p0(i64 1, ptr %z) 713 714 ret void 715} 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 %x 726; GLOBAL-NEXT: %n = load i8, ptr %y 727; 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 4 731 %y = alloca i8, align 4 732 %z = alloca i8, align 4 733 734 call void @llvm.lifetime.start.p0(i64 1, ptr %x) 735 call void @llvm.lifetime.start.p0(i64 1, ptr %y) 736 call void @llvm.lifetime.start.p0(i64 1, ptr %z) 737 738 store i8 5, ptr %x 739 %n = load i8, ptr %y 740 call void @llvm.memset.p0.i32(ptr nonnull %z, i8 0, i32 1, i1 false) 741 742 ret void 743} 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 4 756 %y = alloca i8, align 4 757 %z = alloca i8, align 4 758 759 call void @llvm.lifetime.start.p0(i64 1, ptr %x) 760 call void @llvm.lifetime.start.p0(i64 1, ptr %y) 761 call void @llvm.lifetime.start.p0(i64 1, ptr %z) 762 763 call void @llvm.lifetime.end.p0(i64 1, ptr %x) 764 call void @llvm.lifetime.end.p0(i64 1, ptr %y) 765 call void @llvm.lifetime.end.p0(i64 1, ptr %z) 766 767 store i8 5, ptr %x 768 %n = load i8, ptr %y 769 call void @llvm.memset.p0.i32(ptr nonnull %z, i8 0, i32 1, i1 false) 770 771 ret void 772} 773 774define void @TwoAllocasOK() { 775; CHECK-LABEL: @TwoAllocasOK 776; 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 4 785 %y = alloca i8, align 4 786 call void @llvm.memcpy.p0.p0.i32(ptr %y, ptr %a, i32 1, i1 false) 787 ret void 788} 789 790define void @TwoAllocasOOBDest() { 791; CHECK-LABEL: @TwoAllocasOOBDest 792; 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 4 800 %y = alloca i8, align 4 801 call void @llvm.memcpy.p0.p0.i32(ptr %y, ptr %a, i32 4, i1 false) 802 ret void 803} 804 805define void @TwoAllocasOOBSource() { 806; CHECK-LABEL: @TwoAllocasOOBSource 807; 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 4 815 %y = alloca i8, align 4 816 call void @llvm.memcpy.p0.p0.i32(ptr %a, ptr %y, i32 4, i1 false) 817 ret void 818} 819 820define void @TwoAllocasOOBBoth() { 821; CHECK-LABEL: @TwoAllocasOOBBoth 822; 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 4 830 %y = alloca i8, align 4 831 call void @llvm.memcpy.p0.p0.i32(ptr %y, ptr %a, i32 5, i1 false) 832 ret void 833} 834 835define void @MixedAccesses() { 836; CHECK-LABEL: @MixedAccesses 837; 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 4 845 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 void 848} 849 850define void @MixedAccesses2() { 851; CHECK-LABEL: @MixedAccesses2 852; 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 4 857; CHECK-EMPTY: 858entry: 859 %a = alloca i32, align 4 860 %n1 = load i64, ptr %a, align 4 861 %n2 = load i32, ptr %a, align 4 862 ret void 863} 864 865define void @MixedAccesses3(ptr %func) { 866; CHECK-LABEL: @MixedAccesses3 867; CHECK-NEXT: args uses: 868; CHECK-NEXT: func[]: full-set 869; CHECK-NEXT: allocas uses: 870; CHECK: a[4]: full-set{{$}} 871; GLOBAL-NEXT: safe accesses: 872; GLOBAL-NEXT: load i32, ptr %a, align 4 873; CHECK-EMPTY: 874entry: 875 %a = alloca i32, align 4 876 %n2 = load i32, ptr %a, align 4 877 call void %func(ptr %a) 878 ret void 879} 880 881define void @MixedAccesses4() { 882; CHECK-LABEL: @MixedAccesses4 883; 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 4 889; CHECK-EMPTY: 890entry: 891 %a = alloca i32, align 4 892 %a1 = alloca ptr, align 4 893 %n2 = load i32, ptr %a, align 4 894 store ptr %a, ptr %a1 895 ret void 896} 897 898define ptr @MixedAccesses5(i1 %x, ptr %y) { 899; CHECK-LABEL: @MixedAccesses5 900; CHECK-NEXT: args uses: 901; CHECK: y[]: full-set 902; CHECK-NEXT: allocas uses: 903; CHECK: a[4]: full-set{{$}} 904; GLOBAL-NEXT: safe accesses: 905; GLOBAL-NEXT: load i32, ptr %a, align 4 906; CHECK-EMPTY: 907entry: 908 %a = alloca i32, align 4 909 br i1 %x, label %tlabel, label %flabel 910flabel: 911 %n = load i32, ptr %a, align 4 912 ret ptr %y 913tlabel: 914 ret ptr %a 915} 916 917define void @MixedAccesses6(ptr %arg) { 918; CHECK-LABEL: @MixedAccesses6 919; 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 4 928 call void @llvm.memcpy.p0.p0.i32(ptr %a, ptr %arg, i32 4, i1 false) 929 ret void 930} 931 932define void @MixedAccesses7(i1 %cond, ptr %arg) { 933; SECV doesn't support select, so we consider this non-stack-safe, even through 934; it is. 935; 936; CHECK-LABEL: @MixedAccesses7 937; CHECK-NEXT: args uses: 938; CHECK-NEXT: arg[]: full-set 939; CHECK-NEXT: allocas uses: 940; CHECK: a[4]: full-set 941; GLOBAL-NEXT: safe accesses: 942; CHECK-EMPTY: 943entry: 944 %a = alloca i32, align 4 945 %x1 = select i1 %cond, ptr %arg, ptr %a 946 call void @llvm.memcpy.p0.p0.i32(ptr %x1, ptr %arg, i32 4, i1 false) 947 ret void 948} 949 950define void @NoStackAccess(ptr %arg1, ptr %arg2) { 951; CHECK-LABEL: @NoStackAccess 952; 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 4 962 call void @llvm.memcpy.p0.p0.i32(ptr %arg1, ptr %arg2, i32 4, i1 false) 963 ret void 964} 965 966define void @DoubleLifetime() { 967; CHECK-LABEL: @DoubleLifetime 968; 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 4 976 call void @llvm.lifetime.start.p0(i64 4, ptr %a) 977 call void @llvm.lifetime.end.p0(i64 4, 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(i64 4, ptr %a) 981 call void @llvm.memset.p0.i32(ptr %a, i8 1, i32 4, i1 false) 982 call void @llvm.lifetime.end.p0(i64 4, ptr %a) 983 ret void 984} 985 986define void @DoubleLifetime2() { 987; CHECK-LABEL: @DoubleLifetime2 988; 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 4 996 call void @llvm.lifetime.start.p0(i64 4, ptr %a) 997 call void @llvm.lifetime.end.p0(i64 4, ptr %a) 998 %n = load i32, ptr %a 999 1000 call void @llvm.lifetime.start.p0(i64 4, ptr %a) 1001 call void @llvm.memset.p0.i32(ptr %a, i8 1, i32 4, i1 false) 1002 call void @llvm.lifetime.end.p0(i64 4, ptr %a) 1003 ret void 1004} 1005 1006define void @DoubleLifetime3() { 1007; CHECK-LABEL: @DoubleLifetime3 1008; 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 4 1016 call void @llvm.lifetime.start.p0(i64 4, ptr %a) 1017 call void @llvm.lifetime.end.p0(i64 4, ptr %a) 1018 store i32 5, ptr %a 1019 1020 call void @llvm.lifetime.start.p0(i64 4, ptr %a) 1021 call void @llvm.memset.p0.i32(ptr %a, i8 1, i32 4, i1 false) 1022 call void @llvm.lifetime.end.p0(i64 4, ptr %a) 1023 ret void 1024} 1025 1026define void @DoubleLifetime4() { 1027; CHECK-LABEL: @DoubleLifetime4 1028; 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 4 1036 call void @llvm.lifetime.start.p0(i64 4, ptr %a) 1037 call void @llvm.memset.p0.i32(ptr %a, i8 1, i32 4, i1 false) 1038 call void @llvm.lifetime.end.p0(i64 4, ptr %a) 1039 call void @unknown_call(ptr %a) 1040 ret void 1041} 1042 1043define void @Cmpxchg4Arg(ptr %p) { 1044; CHECK-LABEL: @Cmpxchg4Arg 1045; 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 1 1050; CHECK-EMPTY: 1051entry: 1052 cmpxchg ptr %p, i32 0, i32 1 monotonic monotonic, align 1 1053 ret void 1054} 1055 1056define void @AtomicRMW4Arg(ptr %p) { 1057; CHECK-LABEL: @AtomicRMW4Arg 1058; 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 1 1063; CHECK-EMPTY: 1064entry: 1065 atomicrmw add ptr %p, i32 1 monotonic, align 1 1066 ret void 1067} 1068 1069define void @Cmpxchg4Alloca() { 1070; CHECK-LABEL: @Cmpxchg4Alloca 1071; 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 1 1076; CHECK-EMPTY: 1077entry: 1078 %x = alloca i32, align 4 1079 cmpxchg ptr %x, i32 0, i32 1 monotonic monotonic, align 1 1080 ret void 1081} 1082 1083define void @AtomicRMW4Alloca() { 1084; CHECK-LABEL: @AtomicRMW4Alloca 1085; 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 1 1090; CHECK-EMPTY: 1091entry: 1092 %x = alloca i32, align 4 1093 atomicrmw add ptr %x, i32 1 monotonic, align 1 1094 ret void 1095} 1096 1097define void @StoreArg(ptr %p) { 1098; CHECK-LABEL: @StoreArg 1099; 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 %p 1104; CHECK-EMPTY: 1105entry: 1106 store i32 1, ptr %p 1107 ret void 1108} 1109 1110define void @NonPointer(ptr %p) { 1111; CHECK-LABEL: @NonPointer 1112; 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 i64 1119 call void @unknown_call_int(i64 %int) 1120 ret void 1121} 1122 1123@ifunc = dso_local ifunc i64 (ptr), ptr @ifunc_resolver 1124 1125define dso_local void @CallIfunc(ptr noundef %uaddr) local_unnamed_addr { 1126; CHECK-LABEL: @CallIfunc 1127; CHECK-NEXT: args uses: 1128; CHECK-NEXT: uaddr[]: full-set 1129entry: 1130 tail call i64 @ifunc(ptr noundef %uaddr) 1131 ret void 1132} 1133 1134define dso_local ptr @ifunc_resolver() { 1135entry: 1136 ret ptr null 1137} 1138 1139declare void @llvm.lifetime.start.p0(i64, ptr nocapture) 1140declare void @llvm.lifetime.end.p0(i64, ptr nocapture) 1141