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