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