1; RUN: llc < %s -verify-machineinstrs -stack-symbol-ordering=0 -mtriple="x86_64-pc-linux-gnu" | FileCheck %s 2; RUN: llc < %s -verify-machineinstrs -stack-symbol-ordering=0 -mtriple="x86_64-pc-unknown-elf" | FileCheck %s 3 4; This test is a sanity check to ensure statepoints are generating StackMap 5; sections correctly. This is not intended to be a rigorous test of the 6; StackMap format (see the stackmap tests for that). 7 8target datalayout = "e-i64:64-f80:128-n8:16:32:64-S128" 9 10declare zeroext i1 @return_i1() 11 12define i1 @test(i32 addrspace(1)* %ptr_base, i32 %arg) 13 gc "statepoint-example" { 14; CHECK-LABEL: test: 15; Do we see two spills for the local values and the store to the 16; alloca? 17; CHECK: subq $40, %rsp 18; CHECK: movq $0, 24(%rsp) 19; CHECK: movq %rdi, 16(%rsp) 20; CHECK: movq %rax, 8(%rsp) 21; CHECK: callq return_i1 22; CHECK: addq $40, %rsp 23; CHECK: retq 24entry: 25 %metadata1 = alloca i32 addrspace(1)*, i32 2, align 8 26 store i32 addrspace(1)* null, i32 addrspace(1)** %metadata1 27 %ptr_derived = getelementptr i32, i32 addrspace(1)* %ptr_base, i32 %arg 28 %safepoint_token = tail call token (i64, i32, i1 ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i1f(i64 0, i32 0, i1 ()* @return_i1, i32 0, i32 0, i32 0, i32 2, i32 addrspace(1)* %ptr_base, i32 addrspace(1)* null, i32 addrspace(1)* %ptr_base, i32 addrspace(1)* %ptr_derived, i32 addrspace(1)* null) 29 %call1 = call zeroext i1 @llvm.experimental.gc.result.i1(token %safepoint_token) 30 %a = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 9, i32 9) 31 %b = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 9, i32 10) 32 %c = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 11, i32 11) 33; 34 ret i1 %call1 35} 36 37; This is similar to the previous test except that we have derived pointer as 38; argument to the function. Despite that this can not happen after the 39; RewriteSafepointForGC pass, lowering should be able to handle it anyway. 40define i1 @test_derived_arg(i32 addrspace(1)* %ptr_base, 41 i32 addrspace(1)* %ptr_derived) 42 gc "statepoint-example" { 43; CHECK-LABEL: test_derived_arg 44; Do we see two spills for the local values and the store to the 45; alloca? 46; CHECK: subq $40, %rsp 47; CHECK: movq $0, 24(%rsp) 48; CHECK: movq %rdi, 16(%rsp) 49; CHECK: movq %rsi, 8(%rsp) 50; CHECK: callq return_i1 51; CHECK: addq $40, %rsp 52; CHECK: retq 53entry: 54 %metadata1 = alloca i32 addrspace(1)*, i32 2, align 8 55 store i32 addrspace(1)* null, i32 addrspace(1)** %metadata1 56 %safepoint_token = tail call token (i64, i32, i1 ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i1f(i64 0, i32 0, i1 ()* @return_i1, i32 0, i32 0, i32 0, i32 2, i32 addrspace(1)* %ptr_base, i32 addrspace(1)* null, i32 addrspace(1)* %ptr_base, i32 addrspace(1)* %ptr_derived, i32 addrspace(1)* null) 57 %call1 = call zeroext i1 @llvm.experimental.gc.result.i1(token %safepoint_token) 58 %a = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 9, i32 9) 59 %b = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 9, i32 10) 60 %c = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 11, i32 11) 61; 62 ret i1 %call1 63} 64 65; Simple test case to check that we emit the ID field correctly 66define i1 @test_id() gc "statepoint-example" { 67; CHECK-LABEL: test_id 68entry: 69 %safepoint_token = tail call token (i64, i32, i1 ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i1f(i64 237, i32 0, i1 ()* @return_i1, i32 0, i32 0, i32 0, i32 0) 70 %call1 = call zeroext i1 @llvm.experimental.gc.result.i1(token %safepoint_token) 71 ret i1 %call1 72} 73 74; This test checks that when SP is changed in the function 75; (e.g. passing arguments on stack), the stack map entry 76; takes this adjustment into account. 77declare void @many_arg(i64, i64, i64, i64, i64, i64, i64, i64) 78 79define i32 @test_spadj(i32 addrspace(1)* %p) gc "statepoint-example" { 80 ; CHECK-LABEL: test_spadj 81 ; CHECK: movq %rdi, (%rsp) 82 ; CHECK: xorl %edi, %edi 83 ; CHECK: xorl %esi, %esi 84 ; CHECK: xorl %edx, %edx 85 ; CHECK: xorl %ecx, %ecx 86 ; CHECK: xorl %r8d, %r8d 87 ; CHECK: xorl %r9d, %r9d 88 ; CHECK: pushq $0 89 ; CHECK: pushq $0 90 ; CHECK: callq many_arg 91 ; CHECK: addq $16, %rsp 92 ; CHECK: movq (%rsp) 93 %statepoint_token = call token (i64, i32, void (i64, i64, i64, i64, i64, i64, i64, i64)*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidi64i64i64i64i64i64i64i64f(i64 0, i32 0, void (i64, i64, i64, i64, i64, i64, i64, i64)* @many_arg, i32 8, i32 0, i64 0, i64 0, i64 0, i64 0, i64 0, i64 0, i64 0, i64 0, i32 0, i32 0, i32 addrspace(1)* %p) 94 %p.relocated = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %statepoint_token, i32 15, i32 15) ; (%p, %p) 95 %ld = load i32, i32 addrspace(1)* %p.relocated 96 ret i32 %ld 97} 98 99 100declare token @llvm.experimental.gc.statepoint.p0f_i1f(i64, i32, i1 ()*, i32, i32, ...) 101declare token @llvm.experimental.gc.statepoint.p0f_isVoidi64i64i64i64i64i64i64i64f(i64, i32, void (i64, i64, i64, i64, i64, i64, i64, i64)*, i32, i32, ...) 102declare i1 @llvm.experimental.gc.result.i1(token) 103declare i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token, i32, i32) #3 104 105; CHECK-LABEL: .section .llvm_stackmaps 106; CHECK-NEXT: __LLVM_StackMaps: 107; Header 108; CHECK-NEXT: .byte 3 109; CHECK-NEXT: .byte 0 110; CHECK-NEXT: .short 0 111; Num Functions 112; CHECK-NEXT: .long 4 113; Num LargeConstants 114; CHECK-NEXT: .long 0 115; Num Callsites 116; CHECK-NEXT: .long 4 117 118; Functions and stack size 119; CHECK-NEXT: .quad test 120; CHECK-NEXT: .quad 40 121; CHECK-NEXT: .quad 1 122; CHECK-NEXT: .quad test_derived_arg 123; CHECK-NEXT: .quad 40 124; CHECK-NEXT: .quad 1 125; CHECK-NEXT: .quad test_id 126; CHECK-NEXT: .quad 8 127; CHECK-NEXT: .quad 1 128; CHECK-NEXT: .quad test_spadj 129; CHECK-NEXT: .quad 8 130; CHECK-NEXT: .quad 1 131 132; 133; test 134; 135 136; Statepoint ID 137; CHECK-NEXT: .quad 0 138 139; Callsites 140; Constant arguments 141; CHECK-NEXT: .long .Ltmp0-test 142; CHECK: .short 0 143; CHECK: .short 11 144; SmallConstant (0) 145; CHECK: .byte 4 146; CHECK-NEXT: .byte 0 147; CHECK: .short 8 148; CHECK: .short 0 149; CHECK-NEXT: .short 0 150; CHECK: .long 0 151; SmallConstant (0) 152; CHECK: .byte 4 153; CHECK-NEXT: .byte 0 154; CHECK: .short 8 155; CHECK: .short 0 156; CHECK-NEXT: .short 0 157; CHECK: .long 0 158; SmallConstant (2) 159; CHECK: .byte 4 160; CHECK-NEXT: .byte 0 161; CHECK: .short 8 162; CHECK: .short 0 163; CHECK-NEXT: .short 0 164; CHECK: .long 2 165; Indirect Spill Slot [RSP+0] 166; CHECK: .byte 3 167; CHECK-NEXT: .byte 0 168; CHECK: .short 8 169; CHECK: .short 7 170; CHECK-NEXT: .short 0 171; CHECK: .long 16 172; SmallConstant (0) 173; CHECK: .byte 4 174; CHECK-NEXT: .byte 0 175; CHECK: .short 8 176; CHECK: .short 0 177; CHECK-NEXT: .short 0 178; CHECK: .long 0 179; SmallConstant (0) 180; CHECK: .byte 4 181; CHECK-NEXT: .byte 0 182; CHECK: .short 8 183; CHECK: .short 0 184; CHECK-NEXT: .short 0 185; CHECK: .long 0 186; SmallConstant (0) 187; CHECK: .byte 4 188; CHECK-NEXT: .byte 0 189; CHECK: .short 8 190; CHECK: .short 0 191; CHECK-NEXT: .short 0 192; CHECK: .long 0 193; Indirect Spill Slot [RSP+16] 194; CHECK: .byte 3 195; CHECK-NEXT: .byte 0 196; CHECK: .short 8 197; CHECK: .short 7 198; CHECK-NEXT: .short 0 199; CHECK: .long 16 200; Indirect Spill Slot [RSP+8] 201; CHECK: .byte 3 202; CHECK-NEXT: .byte 0 203; CHECK: .short 8 204; CHECK: .short 7 205; CHECK-NEXT: .short 0 206; CHECK: .long 8 207; Indirect Spill Slot [RSP+16] 208; CHECK: .byte 3 209; CHECK-NEXT: .byte 0 210; CHECK: .short 8 211; CHECK: .short 7 212; CHECK-NEXT: .short 0 213; CHECK: .long 16 214; Indirect Spill Slot [RSP+16] 215; CHECK: .byte 3 216; CHECK-NEXT: .byte 0 217; CHECK: .short 8 218; CHECK: .short 7 219; CHECK-NEXT: .short 0 220; CHECK: .long 16 221 222; No Padding or LiveOuts 223; CHECK: .short 0 224; CHECK: .short 0 225; CHECK: .p2align 3 226 227; 228; test_derived_arg 229 230; Statepoint ID 231; CHECK-NEXT: .quad 0 232 233; Callsites 234; Constant arguments 235; CHECK-NEXT: .long .Ltmp1-test_derived_arg 236; CHECK: .short 0 237; CHECK: .short 11 238; SmallConstant (0) 239; CHECK: .byte 4 240; CHECK-NEXT: .byte 0 241; CHECK: .short 8 242; CHECK: .short 0 243; CHECK-NEXT: .short 0 244; CHECK: .long 0 245; SmallConstant (2) 246; CHECK: .byte 4 247; CHECK-NEXT: .byte 0 248; CHECK: .short 8 249; CHECK: .short 0 250; CHECK-NEXT: .short 0 251; CHECK: .long 2 252; Indirect Spill Slot [RSP+0] 253; CHECK: .byte 3 254; CHECK-NEXT: .byte 0 255; CHECK: .short 8 256; CHECK: .short 7 257; CHECK-NEXT: .short 0 258; CHECK: .long 16 259; SmallConstant (0) 260; CHECK: .byte 4 261; CHECK-NEXT: .byte 0 262; CHECK: .short 8 263; CHECK: .short 0 264; CHECK-NEXT: .short 0 265; CHECK: .long 0 266; SmallConstant (0) 267; CHECK: .byte 4 268; CHECK-NEXT: .byte 0 269; CHECK: .short 8 270; CHECK: .short 0 271; CHECK-NEXT: .short 0 272; CHECK: .long 0 273; SmallConstant (0) 274; CHECK: .byte 4 275; CHECK-NEXT: .byte 0 276; CHECK: .short 8 277; CHECK: .short 0 278; CHECK-NEXT: .short 0 279; CHECK: .long 0 280; Indirect Spill Slot [RSP+16] 281; CHECK: .byte 3 282; CHECK-NEXT: .byte 0 283; CHECK: .short 8 284; CHECK: .short 7 285; CHECK-NEXT: .short 0 286; CHECK: .long 16 287; Indirect Spill Slot [RSP+8] 288; CHECK: .byte 3 289; CHECK-NEXT: .byte 0 290; CHECK: .short 8 291; CHECK: .short 7 292; CHECK-NEXT: .short 0 293; CHECK: .long 8 294; Indirect Spill Slot [RSP+16] 295; CHECK: .byte 3 296; CHECK-NEXT: .byte 0 297; CHECK: .short 8 298; CHECK: .short 7 299; CHECK-NEXT: .short 0 300; CHECK: .long 16 301; Indirect Spill Slot [RSP+16] 302; CHECK: .byte 3 303; CHECK-NEXT: .byte 0 304; CHECK: .short 8 305; CHECK: .short 7 306; CHECK-NEXT: .short 0 307; CHECK: .long 16 308 309; No Padding or LiveOuts 310; CHECK: .short 0 311; CHECK: .short 0 312; CHECK: .p2align 3 313 314; Records for the test_id function: 315 316; The Statepoint ID: 317; CHECK-NEXT: .quad 237 318 319; Instruction Offset 320; CHECK-NEXT: .long .Ltmp2-test_id 321 322; Reserved: 323; CHECK: .short 0 324 325; NumLocations: 326; CHECK: .short 3 327 328; StkMapRecord[0]: 329; SmallConstant(0): 330; CHECK: .byte 4 331; CHECK-NEXT: .byte 0 332; CHECK: .short 8 333; CHECK: .short 0 334; CHECK-NEXT: .short 0 335; CHECK: .long 0 336 337; StkMapRecord[1]: 338; SmallConstant(0): 339; CHECK: .byte 4 340; CHECK-NEXT: .byte 0 341; CHECK: .short 8 342; CHECK: .short 0 343; CHECK-NEXT: .short 0 344; CHECK: .long 0 345 346; StkMapRecord[2]: 347; SmallConstant(0): 348; CHECK: .byte 4 349; CHECK-NEXT: .byte 0 350; CHECK: .short 8 351; CHECK: .short 0 352; CHECK-NEXT: .short 0 353; CHECK: .long 0 354 355; No padding or LiveOuts 356; CHECK: .short 0 357; CHECK: .short 0 358; CHECK: .p2align 3 359 360; 361; test_spadj 362 363; Statepoint ID 364; CHECK-NEXT: .quad 0 365 366; Instruction Offset 367; CHECK-NEXT: .long .Ltmp3-test_spadj 368 369; Reserved: 370; CHECK: .short 0 371 372; NumLocations: 373; CHECK: .short 5 374 375; StkMapRecord[0]: 376; SmallConstant(0): 377; CHECK: .byte 4 378; CHECK-NEXT: .byte 0 379; CHECK: .short 8 380; CHECK: .short 0 381; CHECK-NEXT: .short 0 382; CHECK: .long 0 383 384; StkMapRecord[1]: 385; SmallConstant(0): 386; CHECK: .byte 4 387; CHECK-NEXT: .byte 0 388; CHECK: .short 8 389; CHECK: .short 0 390; CHECK-NEXT: .short 0 391; CHECK: .long 0 392 393; StkMapRecord[2]: 394; SmallConstant(0): 395; CHECK: .byte 4 396; CHECK-NEXT: .byte 0 397; CHECK: .short 8 398; CHECK: .short 0 399; CHECK-NEXT: .short 0 400; CHECK: .long 0 401 402; StkMapRecord[3]: 403; Indirect Spill Slot [RSP+16] 404; CHECK: .byte 3 405; CHECK-NEXT: .byte 0 406; CHECK: .short 8 407; CHECK: .short 7 408; CHECK-NEXT: .short 0 409; CHECK: .long 16 410 411; StkMapRecord[4]: 412; Indirect Spill Slot [RSP+16] 413; CHECK: .byte 3 414; CHECK-NEXT: .byte 0 415; CHECK: .short 8 416; CHECK: .short 7 417; CHECK-NEXT: .short 0 418; CHECK: .long 16 419 420; No padding or LiveOuts 421; CHECK: .short 0 422; CHECK: .short 0 423; CHECK: .p2align 3 424