1; REQUIRES: aarch64-registered-target 2; REQUIRES: shell 3 4; RUN: llvm-as %s -o %t0.bc 5; RUN: llvm-as %S/Inputs/ipa.ll -o %t1.bc 6; RUN: llvm-link -disable-lazy-loading %t0.bc %t1.bc -o %t.combined.bc 7 8; RUN: opt -S -passes="print<stack-safety-local>" -disable-output %t.combined.bc 2>&1 | FileCheck %s --check-prefixes=CHECK,LOCAL 9 10; RUN: opt -S -passes="print-stack-safety" -disable-output %t.combined.bc 2>&1 | FileCheck %s --check-prefixes=CHECK,GLOBAL,NOLTO 11 12; Do an end-to-test using the new LTO API 13; TODO: Hideous llvm-lto2 invocation, add a --default-symbol-resolution to llvm-lto2? 14; RUN: opt -module-summary %s -o %t.summ0.bc 15; RUN: opt -module-summary %S/Inputs/ipa.ll -o %t.summ1.bc 16 17; RUN: llvm-dis %t.summ0.bc -o - > %t.ids.txt 18; RUN: llvm-dis %t.summ1.bc -o - >> %t.ids.txt 19 20; RUN: echo > %t.res.txt \ 21; RUN: -r %t.summ0.bc,ExternalCall, \ 22; RUN: -r %t.summ0.bc,f1,px \ 23; RUN: -r %t.summ0.bc,f2,px \ 24; RUN: -r %t.summ0.bc,f3,px \ 25; RUN: -r %t.summ0.bc,f4,px \ 26; RUN: -r %t.summ0.bc,f5,px \ 27; RUN: -r %t.summ0.bc,f6,px \ 28; RUN: -r %t.summ0.bc,f7,px \ 29; RUN: -r %t.summ0.bc,f8left,px \ 30; RUN: -r %t.summ0.bc,f8oobleft,px \ 31; RUN: -r %t.summ0.bc,f8oobright,px \ 32; RUN: -r %t.summ0.bc,f8right,px \ 33; RUN: -r %t.summ0.bc,InterposableCall,px \ 34; RUN: -r %t.summ0.bc,InterposableWrite1, \ 35; RUN: -r %t.summ0.bc,PreemptableCall,px \ 36; RUN: -r %t.summ0.bc,PreemptableWrite1, \ 37; RUN: -r %t.summ0.bc,PrivateCall,px \ 38; RUN: -r %t.summ0.bc,Rec2, \ 39; RUN: -r %t.summ0.bc,RecursiveNoOffset, \ 40; RUN: -r %t.summ0.bc,RecursiveWithOffset, \ 41; RUN: -r %t.summ0.bc,ReturnDependent, \ 42; RUN: -r %t.summ0.bc,TestCrossModuleConflict,px \ 43; RUN: -r %t.summ0.bc,TestCrossModuleOnce,px \ 44; RUN: -r %t.summ0.bc,TestCrossModuleTwice,px \ 45; RUN: -r %t.summ0.bc,TestCrossModuleWeak,px \ 46; RUN: -r %t.summ0.bc,TestRecursiveNoOffset,px \ 47; RUN: -r %t.summ0.bc,TestRecursiveWithOffset,px \ 48; RUN: -r %t.summ0.bc,TestUpdateArg,px \ 49; RUN: -r %t.summ0.bc,TwoArguments,px \ 50; RUN: -r %t.summ0.bc,TwoArgumentsOOBBoth,px \ 51; RUN: -r %t.summ0.bc,TwoArgumentsOOBOne,px \ 52; RUN: -r %t.summ0.bc,TwoArgumentsOOBOther,px \ 53; RUN: -r %t.summ0.bc,Weak,x \ 54; RUN: -r %t.summ0.bc,Write1, \ 55; RUN: -r %t.summ0.bc,Write1DiffModule,x \ 56; RUN: -r %t.summ0.bc,Write1Module0,px \ 57; RUN: -r %t.summ0.bc,Write1Private,x \ 58; RUN: -r %t.summ0.bc,Write1SameModule,x \ 59; RUN: -r %t.summ0.bc,Write1Weak,x \ 60; RUN: -r %t.summ0.bc,Write4_2, \ 61; RUN: -r %t.summ0.bc,Write4, \ 62; RUN: -r %t.summ0.bc,Write8, \ 63; RUN: -r %t.summ0.bc,WriteAndReturn8, \ 64; RUN: -r %t.summ1.bc,ExternalCall,px \ 65; RUN: -r %t.summ1.bc,InterposableWrite1,px \ 66; RUN: -r %t.summ1.bc,PreemptableWrite1,px \ 67; RUN: -r %t.summ1.bc,Rec0,px \ 68; RUN: -r %t.summ1.bc,Rec1,px \ 69; RUN: -r %t.summ1.bc,Rec2,px \ 70; RUN: -r %t.summ1.bc,RecursiveNoOffset,px \ 71; RUN: -r %t.summ1.bc,RecursiveWithOffset,px \ 72; RUN: -r %t.summ1.bc,ReturnAlloca,px \ 73; RUN: -r %t.summ1.bc,ReturnDependent,px \ 74; RUN: -r %t.summ1.bc,Weak,x \ 75; RUN: -r %t.summ1.bc,Write1,px \ 76; RUN: -r %t.summ1.bc,Write1DiffModule,px \ 77; RUN: -r %t.summ1.bc,Write1Module0,x \ 78; RUN: -r %t.summ1.bc,Write1Private,px \ 79; RUN: -r %t.summ1.bc,Write1SameModule,px \ 80; RUN: -r %t.summ1.bc,Write1Weak,px \ 81; RUN: -r %t.summ1.bc,Write4_2,px \ 82; RUN: -r %t.summ1.bc,Write4,px \ 83; RUN: -r %t.summ1.bc,Write8,px \ 84; RUN: -r %t.summ1.bc,WriteAndReturn8,px 85 86; RUN: llvm-lto2 run %t.summ0.bc %t.summ1.bc -o %t.lto -stack-safety-print -stack-safety-run -save-temps -thinlto-threads 1 -O0 \ 87; RUN: $(cat %t.res.txt) \ 88; RUN: 2>&1 | FileCheck %s --check-prefixes=CHECK,GLOBAL,LTO 89 90; RUN: llvm-lto2 run %t.summ0.bc %t.summ1.bc -o %t.lto -stack-safety-run -thinlto-distributed-indexes -thinlto-threads 1 -O0 $(cat %t.res.txt) 91; RUN: (cat %t.ids.txt ; llvm-dis %t.summ1.bc.thinlto.bc -o -) | FileCheck --check-prefixes=INDEX %s 92 93; RUN: llvm-lto2 run %t.summ0.bc %t.summ1.bc -o %t-newpm.lto -use-new-pm -stack-safety-print -stack-safety-run -save-temps -thinlto-threads 1 -O0 \ 94; RUN: $(cat %t.res.txt) \ 95; RUN: 2>&1 | FileCheck %s --check-prefixes=CHECK,GLOBAL,LTO 96 97; RUN: llvm-lto2 run %t.summ0.bc %t.summ1.bc -o %t-newpm.lto -stack-safety-run -thinlto-distributed-indexes -thinlto-threads 1 -O0 $(cat %t.res.txt) 98; RUN: (cat %t.ids.txt ; llvm-dis %t.summ1.bc.thinlto.bc -o -) | FileCheck --check-prefixes=INDEX %s 99 100target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" 101target triple = "aarch64-unknown-linux" 102 103attributes #0 = { noinline sanitize_memtag "target-features"="+mte,+neon" } 104 105declare void @Write1(i8* %p) 106declare void @Write4(i8* %p) 107declare void @Write4_2(i8* %p, i8* %q) 108declare void @Write8(i8* %p) 109declare dso_local i8* @WriteAndReturn8(i8* %p) 110declare dso_local void @ExternalCall(i8* %p) 111declare void @PreemptableWrite1(i8* %p) 112declare void @InterposableWrite1(i8* %p) 113declare i8* @ReturnDependent(i8* %p) 114declare void @Rec2(i8* %p) 115declare void @RecursiveNoOffset(i32* %p, i32 %size, i32* %acc) 116declare void @RecursiveWithOffset(i32 %size, i32* %acc) 117declare void @Write1SameModule(i8* %p) 118declare void @Write1DiffModule(i8* %p) 119declare void @Write1Private(i8* %p) 120declare void @Write1Weak(i8* %p) 121 122; Basic out-of-bounds. 123define void @f1() #0 { 124; CHECK-LABEL: @f1 dso_preemptable{{$}} 125; CHECK-NEXT: args uses: 126; CHECK-NEXT: allocas uses: 127; LOCAL-NEXT: x[4]: empty-set, @Write8(arg0, [0,1)){{$}} 128; GLOBAL-NEXT: x[4]: [0,8), @Write8(arg0, [0,1)){{$}} 129; GLOBAL-NEXT: safe accesses: 130; CHECK-EMPTY: 131entry: 132 %x = alloca i32, align 4 133 %x1 = bitcast i32* %x to i8* 134 call void @Write8(i8* %x1) 135 ret void 136} 137 138; Basic in-bounds. 139define void @f2() #0 { 140; CHECK-LABEL: @f2 dso_preemptable{{$}} 141; CHECK-NEXT: args uses: 142; CHECK-NEXT: allocas uses: 143; LOCAL-NEXT: x[4]: empty-set, @Write1(arg0, [0,1)){{$}} 144; GLOBAL-NEXT: x[4]: [0,1), @Write1(arg0, [0,1)){{$}} 145; GLOBAL-NEXT: safe accesses: 146; CHECK-EMPTY: 147entry: 148 %x = alloca i32, align 4 149 %x1 = bitcast i32* %x to i8* 150 call void @Write1(i8* %x1) 151 ret void 152} 153 154; Another basic in-bounds. 155define void @f3() #0 { 156; CHECK-LABEL: @f3 dso_preemptable{{$}} 157; CHECK-NEXT: args uses: 158; CHECK-NEXT: allocas uses: 159; LOCAL-NEXT: x[4]: empty-set, @Write4(arg0, [0,1)){{$}} 160; GLOBAL-NEXT: x[4]: [0,4), @Write4(arg0, [0,1)){{$}} 161; GLOBAL-NEXT: safe accesses: 162; CHECK-EMPTY: 163entry: 164 %x = alloca i32, align 4 165 %x1 = bitcast i32* %x to i8* 166 call void @Write4(i8* %x1) 167 ret void 168} 169 170; In-bounds with offset. 171define void @f4() #0 { 172; CHECK-LABEL: @f4 dso_preemptable{{$}} 173; CHECK-NEXT: args uses: 174; CHECK-NEXT: allocas uses: 175; LOCAL-NEXT: x[4]: empty-set, @Write1(arg0, [1,2)){{$}} 176; GLOBAL-NEXT: x[4]: [1,2), @Write1(arg0, [1,2)){{$}} 177; GLOBAL-NEXT: safe accesses: 178; CHECK-EMPTY: 179entry: 180 %x = alloca i32, align 4 181 %x1 = bitcast i32* %x to i8* 182 %x2 = getelementptr i8, i8* %x1, i64 1 183 call void @Write1(i8* %x2) 184 ret void 185} 186 187; Out-of-bounds with offset. 188define void @f5() #0 { 189; CHECK-LABEL: @f5 dso_preemptable{{$}} 190; CHECK-NEXT: args uses: 191; CHECK-NEXT: allocas uses: 192; LOCAL-NEXT: empty-set, @Write4(arg0, [1,2)){{$}} 193; GLOBAL-NEXT: [1,5), @Write4(arg0, [1,2)){{$}} 194; GLOBAL-NEXT: safe accesses: 195; CHECK-EMPTY: 196entry: 197 %x = alloca i32, align 4 198 %x1 = bitcast i32* %x to i8* 199 %x2 = getelementptr i8, i8* %x1, i64 1 200 call void @Write4(i8* %x2) 201 ret void 202} 203 204; External call. 205define void @f6() #0 { 206; CHECK-LABEL: @f6 dso_preemptable{{$}} 207; CHECK-NEXT: args uses: 208; CHECK-NEXT: allocas uses: 209; LOCAL-NEXT: x[4]: empty-set, @ExternalCall(arg0, [0,1)){{$}} 210; GLOBAL-NEXT: x[4]: full-set, @ExternalCall(arg0, [0,1)){{$}} 211; GLOBAL-NEXT: safe accesses: 212; CHECK-EMPTY: 213entry: 214 %x = alloca i32, align 4 215 %x1 = bitcast i32* %x to i8* 216 call void @ExternalCall(i8* %x1) 217 ret void 218} 219 220; Call to dso_preemptable function 221define void @PreemptableCall() #0 { 222; CHECK-LABEL: @PreemptableCall dso_preemptable{{$}} 223; CHECK-NEXT: args uses: 224; CHECK-NEXT: allocas uses: 225; LOCAL-NEXT: x[4]: empty-set, @PreemptableWrite1(arg0, [0,1)){{$}} 226; GLOBAL-NEXT: x[4]: full-set, @PreemptableWrite1(arg0, [0,1)){{$}} 227; GLOBAL-NEXT: safe accesses: 228; CHECK-EMPTY: 229entry: 230 %x = alloca i32, align 4 231 %x1 = bitcast i32* %x to i8* 232 call void @PreemptableWrite1(i8* %x1) 233 ret void 234} 235 236; Call to function with interposable linkage 237define void @InterposableCall() #0 { 238; CHECK-LABEL: @InterposableCall dso_preemptable{{$}} 239; CHECK-NEXT: args uses: 240; CHECK-NEXT: allocas uses: 241; LOCAL-NEXT: x[4]: empty-set, @InterposableWrite1(arg0, [0,1)){{$}} 242; NOLTO-NEXT: x[4]: full-set, @InterposableWrite1(arg0, [0,1)){{$}} 243; LTO-NEXT: x[4]: [0,1), @InterposableWrite1(arg0, [0,1)){{$}} 244; GLOBAL-NEXT: safe accesses: 245; CHECK-EMPTY: 246entry: 247 %x = alloca i32, align 4 248 %x1 = bitcast i32* %x to i8* 249 call void @InterposableWrite1(i8* %x1) 250 ret void 251} 252 253; Call to function with private linkage 254define void @PrivateCall() #0 { 255; CHECK-LABEL: @PrivateCall dso_preemptable{{$}} 256; CHECK-NEXT: args uses: 257; CHECK-NEXT: allocas uses: 258; LOCAL-NEXT: x[4]: empty-set, @PrivateWrite1(arg0, [0,1)){{$}} 259; GLOBAL-NEXT: x[4]: [0,1), @PrivateWrite1(arg0, [0,1)){{$}} 260; GLOBAL-NEXT: safe accesses: 261; CHECK-EMPTY: 262entry: 263 %x = alloca i32, align 4 264 %x1 = bitcast i32* %x to i8* 265 call void @PrivateWrite1(i8* %x1) 266 ret void 267} 268 269define private void @PrivateWrite1(i8* %p) #0 { 270; CHECK-LABEL: @PrivateWrite1{{$}} 271; CHECK-NEXT: args uses: 272; CHECK-NEXT: p[]: [0,1){{$}} 273; CHECK-NEXT: allocas uses: 274; GLOBAL-NEXT: safe accesses: 275; GLOBAL-NEXT: store i8 0, i8* %p, align 1 276; CHECK-EMPTY: 277entry: 278 store i8 0, i8* %p, align 1 279 ret void 280} 281 282; Caller returns a dependent value. 283; FIXME: alloca considered unsafe even if the return value is unused. 284define void @f7() #0 { 285; CHECK-LABEL: @f7 dso_preemptable{{$}} 286; CHECK-NEXT: args uses: 287; CHECK-NEXT: allocas uses: 288; LOCAL-NEXT: x[4]: empty-set, @ReturnDependent(arg0, [0,1)){{$}} 289; GLOBAL-NEXT: x[4]: full-set, @ReturnDependent(arg0, [0,1)){{$}} 290; GLOBAL-NEXT: safe accesses: 291; CHECK-EMPTY: 292entry: 293 %x = alloca i32, align 4 294 %x1 = bitcast i32* %x to i8* 295 %x2 = call i8* @ReturnDependent(i8* %x1) 296 ret void 297} 298 299define void @f8left() #0 { 300; CHECK-LABEL: @f8left dso_preemptable{{$}} 301; CHECK-NEXT: args uses: 302; CHECK-NEXT: allocas uses: 303; LOCAL-NEXT: x[8]: empty-set, @Rec2(arg0, [2,3)){{$}} 304; GLOBAL-NEXT: x[8]: [0,4), @Rec2(arg0, [2,3)){{$}} 305; GLOBAL-NEXT: safe accesses: 306; CHECK-EMPTY: 307entry: 308 %x = alloca i64, align 4 309 %x1 = bitcast i64* %x to i8* 310 %x2 = getelementptr i8, i8* %x1, i64 2 311; 2 + [-2, 2) = [0, 4) => OK 312 call void @Rec2(i8* %x2) 313 ret void 314} 315 316define void @f8right() #0 { 317; CHECK-LABEL: @f8right dso_preemptable{{$}} 318; CHECK-NEXT: args uses: 319; CHECK-NEXT: allocas uses: 320; LOCAL-NEXT: x[8]: empty-set, @Rec2(arg0, [6,7)){{$}} 321; GLOBAL-NEXT: x[8]: [4,8), @Rec2(arg0, [6,7)){{$}} 322; GLOBAL-NEXT: safe accesses: 323; CHECK-EMPTY: 324entry: 325 %x = alloca i64, align 4 326 %x1 = bitcast i64* %x to i8* 327 %x2 = getelementptr i8, i8* %x1, i64 6 328; 6 + [-2, 2) = [4, 8) => OK 329 call void @Rec2(i8* %x2) 330 ret void 331} 332 333define void @f8oobleft() #0 { 334; CHECK-LABEL: @f8oobleft dso_preemptable{{$}} 335; CHECK-NEXT: args uses: 336; CHECK-NEXT: allocas uses: 337; LOCAL-NEXT: x[8]: empty-set, @Rec2(arg0, [1,2)){{$}} 338; GLOBAL-NEXT: x[8]: [-1,3), @Rec2(arg0, [1,2)){{$}} 339; GLOBAL-NEXT: safe accesses: 340; CHECK-EMPTY: 341entry: 342 %x = alloca i64, align 4 343 %x1 = bitcast i64* %x to i8* 344 %x2 = getelementptr i8, i8* %x1, i64 1 345; 1 + [-2, 2) = [-1, 3) => NOT OK 346 call void @Rec2(i8* %x2) 347 ret void 348} 349 350define void @f8oobright() #0 { 351; CHECK-LABEL: @f8oobright dso_preemptable{{$}} 352; CHECK-NEXT: args uses: 353; CHECK-NEXT: allocas uses: 354; LOCAL-NEXT: x[8]: empty-set, @Rec2(arg0, [7,8)){{$}} 355; GLOBAL-NEXT: x[8]: [5,9), @Rec2(arg0, [7,8)){{$}} 356; GLOBAL-NEXT: safe accesses: 357; CHECK-EMPTY: 358entry: 359 %x = alloca i64, align 4 360 %x1 = bitcast i64* %x to i8* 361 %x2 = getelementptr i8, i8* %x1, i64 7 362; 7 + [-2, 2) = [5, 9) => NOT OK 363 call void @Rec2(i8* %x2) 364 ret void 365} 366 367define void @TwoArguments() #0 { 368; CHECK-LABEL: @TwoArguments dso_preemptable{{$}} 369; CHECK-NEXT: args uses: 370; CHECK-NEXT: allocas uses: 371; LOCAL-NEXT: x[8]: empty-set, @Write4_2(arg0, [4,5)), @Write4_2(arg1, [0,1)){{$}} 372; GLOBAL-NEXT: x[8]: [0,8), @Write4_2(arg0, [4,5)), @Write4_2(arg1, [0,1)){{$}} 373; GLOBAL-NEXT: safe accesses: 374; CHECK-EMPTY: 375entry: 376 %x = alloca i64, align 4 377 %x1 = bitcast i64* %x to i8* 378 %x2 = getelementptr i8, i8* %x1, i64 4 379 call void @Write4_2(i8* %x2, i8* %x1) 380 ret void 381} 382 383define void @TwoArgumentsOOBOne() #0 { 384; CHECK-LABEL: @TwoArgumentsOOBOne dso_preemptable{{$}} 385; CHECK-NEXT: args uses: 386; CHECK-NEXT: allocas uses: 387; LOCAL-NEXT: x[8]: empty-set, @Write4_2(arg0, [5,6)), @Write4_2(arg1, [0,1)){{$}} 388; GLOBAL-NEXT: x[8]: [0,9), @Write4_2(arg0, [5,6)), @Write4_2(arg1, [0,1)){{$}} 389; GLOBAL-NEXT: safe accesses: 390; CHECK-EMPTY: 391entry: 392 %x = alloca i64, align 4 393 %x1 = bitcast i64* %x to i8* 394 %x2 = getelementptr i8, i8* %x1, i64 5 395 call void @Write4_2(i8* %x2, i8* %x1) 396 ret void 397} 398 399define void @TwoArgumentsOOBOther() #0 { 400; CHECK-LABEL: @TwoArgumentsOOBOther dso_preemptable{{$}} 401; CHECK-NEXT: args uses: 402; CHECK-NEXT: allocas uses: 403; LOCAL-NEXT: x[8]: empty-set, @Write4_2(arg0, [4,5)), @Write4_2(arg1, [-1,0)){{$}} 404; GLOBAL-NEXT: x[8]: [-1,8), @Write4_2(arg0, [4,5)), @Write4_2(arg1, [-1,0)){{$}} 405; GLOBAL-NEXT: safe accesses: 406; CHECK-EMPTY: 407entry: 408 %x = alloca i64, align 4 409 %x0 = bitcast i64* %x to i8* 410 %x1 = getelementptr i8, i8* %x0, i64 -1 411 %x2 = getelementptr i8, i8* %x0, i64 4 412 call void @Write4_2(i8* %x2, i8* %x1) 413 ret void 414} 415 416define void @TwoArgumentsOOBBoth() #0 { 417; CHECK-LABEL: @TwoArgumentsOOBBoth dso_preemptable{{$}} 418; CHECK-NEXT: args uses: 419; CHECK-NEXT: allocas uses: 420; LOCAL-NEXT: x[8]: empty-set, @Write4_2(arg0, [5,6)), @Write4_2(arg1, [-1,0)){{$}} 421; GLOBAL-NEXT: x[8]: [-1,9), @Write4_2(arg0, [5,6)), @Write4_2(arg1, [-1,0)){{$}} 422; GLOBAL-NEXT: safe accesses: 423; CHECK-EMPTY: 424entry: 425 %x = alloca i64, align 4 426 %x0 = bitcast i64* %x to i8* 427 %x1 = getelementptr i8, i8* %x0, i64 -1 428 %x2 = getelementptr i8, i8* %x0, i64 5 429 call void @Write4_2(i8* %x2, i8* %x1) 430 ret void 431} 432 433define i32 @TestRecursiveNoOffset(i32* %p, i32 %size) #0 { 434; CHECK-LABEL: @TestRecursiveNoOffset dso_preemptable{{$}} 435; CHECK-NEXT: args uses: 436; LOCAL-NEXT: p[]: empty-set, @RecursiveNoOffset(arg0, [0,1)){{$}} 437; GLOBAL-NEXT: p[]: full-set, @RecursiveNoOffset(arg0, [0,1)){{$}} 438; CHECK-NEXT: allocas uses: 439; CHECK-NEXT: sum[4]: [0,4), @RecursiveNoOffset(arg2, [0,1)){{$}} 440; GLOBAL-NEXT: safe accesses: 441; GLOBAL-NEXT: store i32 0, i32* %sum, align 4 442; GLOBAL-NEXT: %1 = load i32, i32* %sum, align 4 443; CHECK-EMPTY: 444entry: 445 %sum = alloca i32, align 4 446 %0 = bitcast i32* %sum to i8* 447 store i32 0, i32* %sum, align 4 448 call void @RecursiveNoOffset(i32* %p, i32 %size, i32* %sum) 449 %1 = load i32, i32* %sum, align 4 450 ret i32 %1 451} 452 453define void @TestRecursiveWithOffset(i32 %size) #0 { 454; CHECK-LABEL: @TestRecursiveWithOffset dso_preemptable{{$}} 455; CHECK-NEXT: args uses: 456; CHECK-NEXT: allocas uses: 457; LOCAL-NEXT: sum[64]: empty-set, @RecursiveWithOffset(arg1, [0,1)){{$}} 458; GLOBAL-NEXT: sum[64]: full-set, @RecursiveWithOffset(arg1, [0,1)){{$}} 459; GLOBAL-NEXT: safe accesses: 460; CHECK-EMPTY: 461entry: 462 %sum = alloca i32, i64 16, align 4 463 call void @RecursiveWithOffset(i32 %size, i32* %sum) 464 ret void 465} 466 467; FIXME: IPA should detect that access is safe 468define void @TestUpdateArg() #0 { 469; CHECK-LABEL: @TestUpdateArg dso_preemptable{{$}} 470; CHECK-NEXT: args uses: 471; CHECK-NEXT: allocas uses: 472; LOCAL-NEXT: x[16]: empty-set, @WriteAndReturn8(arg0, [0,1)){{$}} 473; GLOBAL-NEXT: x[16]: full-set, @WriteAndReturn8(arg0, [0,1)){{$}} 474; GLOBAL-NEXT: safe accesses: 475; CHECK-EMPTY: 476entry: 477 %x = alloca i8, i64 16, align 4 478 %0 = call i8* @WriteAndReturn8(i8* %x) 479 ret void 480} 481 482define void @TestCrossModuleOnce() #0 { 483; CHECK-DAG: @TestCrossModuleOnce dso_preemptable{{$}} 484; CHECK-NEXT: args uses: 485; CHECK-NEXT: allocas uses: 486; LOCAL-NEXT: y[1]: empty-set, @Write1SameModule(arg0, [0,1)){{$}} 487; GLOBAL-NEXT: y[1]: [0,1), @Write1SameModule(arg0, [0,1)){{$}} 488; GLOBAL-NEXT: safe accesses: 489; CHECK-EMPTY: 490entry: 491 %y = alloca i8, align 4 492 call void @Write1SameModule(i8* %y) 493 ret void 494} 495 496define void @TestCrossModuleTwice() #0 { 497; CHECK-DAG: @TestCrossModuleTwice dso_preemptable{{$}} 498; CHECK-NEXT: args uses: 499; CHECK-NEXT: allocas uses: 500; LOCAL-NEXT: z[1]: empty-set, @Write1DiffModule(arg0, [0,1)){{$}} 501; GLOBAL-NEXT: z[1]: [0,1), @Write1DiffModule(arg0, [0,1)){{$}} 502; GLOBAL-NEXT: safe accesses: 503; CHECK-EMPTY: 504entry: 505 %z = alloca i8, align 4 506 call void @Write1DiffModule(i8* %z) 507 ret void 508} 509 510define void @TestCrossModuleConflict() #0 { 511; CHECK-DAG: @TestCrossModuleConflict dso_preemptable{{$}} 512; CHECK-NEXT: args uses: 513; CHECK-NEXT: allocas uses: 514; LOCAL-NEXT: x[1]: empty-set, @Write1Private(arg0, [0,1)){{$}} 515; GLOBAL-NEXT: x[1]: [-1,0), @Write1Private(arg0, [0,1)){{$}} 516; GLOBAL-NEXT: safe accesses: 517; CHECK-EMPTY: 518entry: 519 %x = alloca i8, align 4 520 call void @Write1Private(i8* %x) 521 ret void 522} 523 524; FIXME: LTO should match NOLTO 525define void @TestCrossModuleWeak() #0 { 526; CHECK-DAG: @TestCrossModuleWeak dso_preemptable{{$}} 527; CHECK-NEXT: args uses: 528; CHECK-NEXT: allocas uses: 529; LOCAL-NEXT: x[1]: empty-set, @Write1Weak(arg0, [0,1)){{$}} 530; NOLTO-NEXT: x[1]: [1,2), @Write1Weak(arg0, [0,1)){{$}} 531; LTO-NEXT: x[1]: full-set, @Write1Weak(arg0, [0,1)){{$}} 532; GLOBAL-NEXT: safe accesses: 533; CHECK-EMPTY: 534entry: 535 %x = alloca i8, align 4 536 call void @Write1Weak(i8* %x) 537 ret void 538} 539 540define private dso_local void @Private(i8* %p) #0 { 541entry: 542 %p1 = getelementptr i8, i8* %p, i64 1 543 store i8 0, i8* %p1, align 1 544 ret void 545} 546 547define dso_local void @Write1Module0(i8* %p) #0 { 548entry: 549 store i8 0, i8* %p, align 1 550 ret void 551} 552 553define dso_local void @Weak(i8* %p) #0 { 554entry: 555 %p1 = getelementptr i8, i8* %p, i64 1 556 store i8 0, i8* %p1, align 1 557 ret void 558} 559 560; The rest is from Inputs/ipa.ll 561 562; CHECK-LABEL: @Write1{{$}} 563; CHECK-NEXT: args uses: 564; CHECK-NEXT: p[]: [0,1){{$}} 565; CHECK-NEXT: allocas uses: 566; GLOBAL-NEXT: safe accesses: 567; GLOBAL-NEXT: store i8 0, i8* %p, align 1 568; CHECK-EMPTY: 569 570; CHECK-LABEL: @Write4{{$}} 571; CHECK-NEXT: args uses: 572; CHECK-NEXT: p[]: [0,4){{$}} 573; CHECK-NEXT: allocas uses: 574; GLOBAL-NEXT: safe accesses: 575; GLOBAL-NEXT: store i32 0, i32* %0, align 1 576; CHECK-EMPTY: 577 578; CHECK-LABEL: @Write4_2{{$}} 579; CHECK-NEXT: args uses: 580; CHECK-NEXT: p[]: [0,4){{$}} 581; CHECK-NEXT: q[]: [0,4){{$}} 582; CHECK-NEXT: allocas uses: 583; GLOBAL-NEXT: safe accesses: 584; GLOBAL-NEXT: store i32 0, i32* %0, align 1 585; GLOBAL-NEXT: store i32 0, i32* %1, align 1 586; CHECK-EMPTY: 587 588; CHECK-LABEL: @Write8{{$}} 589; CHECK-NEXT: args uses: 590; CHECK-NEXT: p[]: [0,8){{$}} 591; CHECK-NEXT: allocas uses: 592; GLOBAL-NEXT: safe accesses: 593; GLOBAL-NEXT: store i64 0, i64* %0, align 1 594; CHECK-EMPTY: 595 596; CHECK-LABEL: @WriteAndReturn8{{$}} 597; CHECK-NEXT: args uses: 598; CHECK-NEXT: p[]: full-set{{$}} 599; CHECK-NEXT: allocas uses: 600; GLOBAL-NEXT: safe accesses: 601; GLOBAL-NEXT: store i8 0, i8* %p, align 1 602; CHECK-EMPTY: 603 604; CHECK-LABEL: @PreemptableWrite1 dso_preemptable{{$}} 605; CHECK-NEXT: args uses: 606; CHECK-NEXT: p[]: [0,1){{$}} 607; CHECK-NEXT: allocas uses: 608; GLOBAL-NEXT: safe accesses: 609; GLOBAL-NEXT: store i8 0, i8* %p, align 1 610; CHECK-EMPTY: 611 612; CHECK-LABEL: @InterposableWrite1 interposable{{$}} 613; CHECK-NEXT: args uses: 614; CHECK-NEXT: p[]: [0,1){{$}} 615; CHECK-NEXT: allocas uses: 616; GLOBAL-NEXT: safe accesses: 617; GLOBAL-NEXT: store i8 0, i8* %p, align 1 618; CHECK-EMPTY: 619 620; CHECK-LABEL: @ReturnDependent{{$}} 621; CHECK-NEXT: args uses: 622; CHECK-NEXT: p[]: full-set{{$}} 623; CHECK-NEXT: allocas uses: 624; GLOBAL-NEXT: safe accesses: 625; CHECK-EMPTY: 626 627; CHECK-LABEL: @Rec0{{$}} 628; CHECK-NEXT: args uses: 629; LOCAL-NEXT: p[]: empty-set, @Write4(arg0, [2,3)){{$}} 630; GLOBAL-NEXT: p[]: [2,6) 631; CHECK-NEXT: allocas uses: 632; GLOBAL-NEXT: safe accesses: 633; CHECK-EMPTY: 634 635; CHECK-LABEL: @Rec1{{$}} 636; CHECK-NEXT: args uses: 637; LOCAL-NEXT: p[]: empty-set, @Rec0(arg0, [1,2)){{$}} 638; GLOBAL-NEXT: p[]: [3,7) 639; CHECK-NEXT: allocas uses: 640; GLOBAL-NEXT: safe accesses: 641; CHECK-EMPTY: 642 643; CHECK-LABEL: @Rec2{{$}} 644; CHECK-NEXT: args uses: 645; LOCAL-NEXT: p[]: empty-set, @Rec1(arg0, [-5,-4)){{$}} 646; GLOBAL-NEXT: p[]: [-2,2) 647; CHECK-NEXT: allocas uses: 648; GLOBAL-NEXT: safe accesses: 649; CHECK-EMPTY: 650 651; CHECK-LABEL: @RecursiveNoOffset{{$}} 652; CHECK-NEXT: args uses: 653; LOCAL-NEXT: p[]: [0,4), @RecursiveNoOffset(arg0, [4,5)){{$}} 654; GLOBAL-NEXT: p[]: full-set, @RecursiveNoOffset(arg0, [4,5)){{$}} 655; CHECK-NEXT: acc[]: [0,4), @RecursiveNoOffset(arg2, [0,1)){{$}} 656; CHECK-NEXT: allocas uses: 657; GLOBAL-NEXT: safe accesses: 658; GLOBAL-NEXT: %0 = load i32, i32* %p, align 4 659; GLOBAL-NEXT: %1 = load i32, i32* %acc, align 4 660; GLOBAL-NEXT: store i32 %add, i32* %acc, align 4 661; CHECK-EMPTY: 662 663; CHECK-LABEL: @RecursiveWithOffset{{$}} 664; CHECK-NEXT: args uses: 665; LOCAL-NEXT: acc[]: [0,4), @RecursiveWithOffset(arg1, [4,5)){{$}} 666; GLOBAL-NEXT: acc[]: full-set, @RecursiveWithOffset(arg1, [4,5)){{$}} 667; CHECK-NEXT: allocas uses: 668; GLOBAL-NEXT: safe accesses: 669; GLOBAL-NEXT: store i32 0, i32* %acc, align 4 670; CHECK-EMPTY: 671 672; CHECK-LABEL: @ReturnAlloca 673; CHECK-NEXT: args uses: 674; CHECK-NEXT: allocas uses: 675; CHECK-NEXT: x[8]: full-set 676; GLOBAL-NEXT: safe accesses: 677; CHECK-EMPTY: 678 679; INDEX-LABEL: ^0 = module: 680; INDEX-DAG: name: "ReturnDependent"{{.*}} guid = [[ReturnDependent:[-0-9]+]] 681; INDEX-DAG: name: "Private"{{.*}} guid = [[Private:[-0-9]+]] 682; INDEX-DAG: name: "TwoArgumentsOOBOther"{{.*}} guid = [[TwoArgumentsOOBOther:[-0-9]+]] 683; INDEX-DAG: name: "Rec2"{{.*}} guid = [[Rec2:[-0-9]+]] 684; INDEX-DAG: name: "f1"{{.*}} guid = [[f1:[-0-9]+]] 685; INDEX-DAG: name: "PrivateWrite1"{{.*}} guid = [[PrivateWrite1:[-0-9]+]] 686; INDEX-DAG: name: "TestRecursiveNoOffset"{{.*}} guid = [[TestRecursiveNoOffset:[-0-9]+]] 687; INDEX-DAG: name: "f8left"{{.*}} guid = [[f8left:[-0-9]+]] 688; INDEX-DAG: name: "Write4"{{.*}} guid = [[Write4:[-0-9]+]] 689; INDEX-DAG: name: "f7"{{.*}} guid = [[f7:[-0-9]+]] 690; INDEX-DAG: name: "Write1SameModule"{{.*}} guid = [[Write1SameModule:[-0-9]+]] 691; INDEX-DAG: name: "Write8"{{.*}} guid = [[Write8:[-0-9]+]] 692; INDEX-DAG: name: "TwoArgumentsOOBOne"{{.*}} guid = [[TwoArgumentsOOBOne:[-0-9]+]] 693; INDEX-DAG: name: "f3"{{.*}} guid = [[f3:[-0-9]+]] 694; INDEX-DAG: name: "f8right"{{.*}} guid = [[f8right:[-0-9]+]] 695; INDEX-DAG: name: "Write4_2"{{.*}} guid = [[Write4_2:[-0-9]+]] 696; INDEX-DAG: name: "RecursiveWithOffset"{{.*}} guid = [[RecursiveWithOffset:[-0-9]+]] 697; INDEX-DAG: name: "Weak"{{.*}} guid = [[Weak:[-0-9]+]] 698; INDEX-DAG: name: "Write1Private"{{.*}} guid = [[Write1Private:[-0-9]+]] 699; INDEX-DAG: name: "TestUpdateArg"{{.*}} guid = [[TestUpdateArg:[-0-9]+]] 700; INDEX-DAG: name: "TestCrossModuleTwice"{{.*}} guid = [[TestCrossModuleTwice:[-0-9]+]] 701; INDEX-DAG: name: "TestCrossModuleWeak"{{.*}} guid = [[TestCrossModuleWeak:[-0-9]+]] 702; INDEX-DAG: name: "f2"{{.*}} guid = [[f2:[-0-9]+]] 703; INDEX-DAG: name: "PrivateCall"{{.*}} guid = [[PrivateCall:[-0-9]+]] 704; INDEX-DAG: name: "TestRecursiveWithOffset"{{.*}} guid = [[TestRecursiveWithOffset:[-0-9]+]] 705; INDEX-DAG: name: "f8oobleft"{{.*}} guid = [[f8oobleft:[-0-9]+]] 706; INDEX-DAG: name: "InterposableWrite1"{{.*}} guid = [[InterposableWrite1:[-0-9]+]] 707; INDEX-DAG: name: "f4"{{.*}} guid = [[f4:[-0-9]+]] 708; INDEX-DAG: name: "TestCrossModuleConflict"{{.*}} guid = [[TestCrossModuleConflict:[-0-9]+]] 709; INDEX-DAG: name: "RecursiveNoOffset"{{.*}} guid = [[RecursiveNoOffset:[-0-9]+]] 710; INDEX-DAG: name: "TwoArgumentsOOBBoth"{{.*}} guid = [[TwoArgumentsOOBBoth:[-0-9]+]] 711; INDEX-DAG: name: "f5"{{.*}} guid = [[f5:[-0-9]+]] 712; INDEX-DAG: name: "f6"{{.*}} guid = [[f6:[-0-9]+]] 713; INDEX-DAG: name: "Write1Weak"{{.*}} guid = [[Write1Weak:[-0-9]+]] 714; INDEX-DAG: name: "Write1"{{.*}} guid = [[Write1:[-0-9]+]] 715; INDEX-DAG: name: "PreemptableWrite1"{{.*}} guid = [[PreemptableWrite1:[-0-9]+]] 716; INDEX-DAG: name: "f8oobright"{{.*}} guid = [[f8oobright:[-0-9]+]] 717; INDEX-DAG: name: "InterposableCall"{{.*}} guid = [[InterposableCall:[-0-9]+]] 718; INDEX-DAG: name: "TestCrossModuleOnce"{{.*}} guid = [[TestCrossModuleOnce:[-0-9]+]] 719; INDEX-DAG: name: "WriteAndReturn8"{{.*}} guid = [[WriteAndReturn8:[-0-9]+]] 720; INDEX-DAG: name: "TwoArguments"{{.*}} guid = [[TwoArguments:[-0-9]+]] 721; INDEX-DAG: name: "Write1Module0"{{.*}} guid = [[Write1Module0:[-0-9]+]] 722; INDEX-DAG: name: "PreemptableCall"{{.*}} guid = [[PreemptableCall:[-0-9]+]] 723; INDEX-DAG: name: "Write1DiffModule"{{.*}} guid = [[Write1DiffModule:[-0-9]+]] 724; INDEX-DAG: name: "ExternalCall"{{.*}} guid = [[ExternalCall:[-0-9]+]] 725; INDEX-LABEL: = blockcount: 726 727; INDEX-LABEL: ^0 = module: 728; INDEX-DAG: name: "ReturnDependent"{{.*}} guid = [[ReturnDependent:[-0-9]+]] 729; INDEX-DAG: name: "Rec0"{{.*}} guid = [[Rec0:[-0-9]+]] 730; INDEX-DAG: name: "Rec2"{{.*}} guid = [[Rec2:[-0-9]+]] 731; INDEX-DAG: name: "Write4"{{.*}} guid = [[Write4:[-0-9]+]] 732; INDEX-DAG: name: "Write1SameModule"{{.*}} guid = [[Write1SameModule:[-0-9]+]] 733; INDEX-DAG: name: "Write8"{{.*}} guid = [[Write8:[-0-9]+]] 734; INDEX-DAG: name: "Write4_2"{{.*}} guid = [[Write4_2:[-0-9]+]] 735; INDEX-DAG: name: "RecursiveWithOffset"{{.*}} guid = [[RecursiveWithOffset:[-0-9]+]] 736; INDEX-DAG: name: "Weak"{{.*}} guid = [[Weak:[-0-9]+]] 737; INDEX-DAG: name: "Write1Private"{{.*}} guid = [[Write1Private:[-0-9]+]] 738; INDEX-DAG: name: "InterposableWrite1"{{.*}} guid = [[InterposableWrite1:[-0-9]+]] 739; INDEX-DAG: name: "Private"{{.*}} guid = [[Private:[-0-9]+]] 740; INDEX-DAG: name: "Rec1"{{.*}} guid = [[Rec1:[-0-9]+]] 741; INDEX-DAG: name: "RecursiveNoOffset"{{.*}} guid = [[RecursiveNoOffset:[-0-9]+]] 742; INDEX-DAG: name: "Write1Weak"{{.*}} guid = [[Write1Weak:[-0-9]+]] 743; INDEX-DAG: name: "Write1"{{.*}} guid = [[Write1:[-0-9]+]] 744; INDEX-DAG: name: "PreemptableWrite1"{{.*}} guid = [[PreemptableWrite1:[-0-9]+]] 745; INDEX-DAG: name: "WriteAndReturn8"{{.*}} guid = [[WriteAndReturn8:[-0-9]+]] 746; INDEX-DAG: name: "Write1Module0"{{.*}} guid = [[Write1Module0:[-0-9]+]] 747; INDEX-DAG: name: "Write1DiffModule"{{.*}} guid = [[Write1DiffModule:[-0-9]+]] 748; INDEX-DAG: name: "ExternalCall"{{.*}} guid = [[ExternalCall:[-0-9]+]] 749; INDEX-DAG: name: "ReturnAlloca"{{.*}} guid = [[ReturnAlloca:[-0-9]+]] 750; INDEX-LABEL: = blockcount: 751 752; INDEX-LABEL: ^0 = module: 753; INDEX-DAG: guid: [[ReturnDependent]], {{.*}}, funcFlags: ({{.*}})))) 754; INDEX-DAG: guid: [[Rec0]], {{.*}}, params: ((param: 0, offset: [2, 5]))))) 755; INDEX-DAG: guid: [[Rec2]], {{.*}}, params: ((param: 0, offset: [-2, 1]))))) 756; INDEX-DAG: guid: [[Write4]], {{.*}}, params: ((param: 0, offset: [0, 3]))))) 757; INDEX-DAG: guid: [[Write1SameModule]], {{.*}}, params: ((param: 0, offset: [0, 0]))))) 758; INDEX-DAG: guid: [[Write8]], {{.*}}, params: ((param: 0, offset: [0, 7]))))) 759; INDEX-DAG: guid: [[Write4_2]], {{.*}}, params: ((param: 0, offset: [0, 3]), (param: 1, offset: [0, 3]))))) 760; INDEX-DAG: guid: [[RecursiveWithOffset]], {{.*}}, calls: ((callee: ^{{[0-9]+}}))))) 761; INDEX-DAG: guid: [[Weak]], {{.*}}, funcFlags: ({{.*}})))) 762; INDEX-DAG: guid: [[Write1Private]], {{.*}}, params: ((param: 0, offset: [-1, -1]))))) 763; INDEX-DAG: guid: [[InterposableWrite1]], {{.*}}, params: ((param: 0, offset: [0, 0]))))) 764; INDEX-DAG: guid: [[Private]], {{.*}}, params: ((param: 0, offset: [-1, -1]))))) 765; INDEX-DAG: guid: [[Rec1]], {{.*}}, params: ((param: 0, offset: [3, 6]))))) 766; INDEX-DAG: guid: [[RecursiveNoOffset]], {{.*}}, params: ((param: 2, offset: [0, 3]))))) 767; INDEX-DAG: guid: [[Write1Weak]], {{.*}}, calls: ((callee: ^{{[0-9]+}}))))) 768; INDEX-DAG: guid: [[Write1]], {{.*}}, params: ((param: 0, offset: [0, 0]))))) 769; INDEX-DAG: guid: [[PreemptableWrite1]], {{.*}}, funcFlags: ({{.*}})))) 770; INDEX-DAG: guid: [[WriteAndReturn8]], {{.*}}, funcFlags: ({{.*}})))) 771; INDEX-DAG: guid: [[Write1DiffModule]], {{.*}}, funcFlags: ({{.*}})))) 772; INDEX-DAG: guid: [[ReturnAlloca]], {{.*}}, insts: 2))) 773; INDEX-LABEL: blockcount: 774