1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 2; RUN: llc -verify-machineinstrs < %s | FileCheck %s 3; This file contains a collection of basic tests to ensure we didn't 4; screw up normal call lowering when there are no deopt or gc arguments. 5 6target datalayout = "e-i64:64-f80:128-n8:16:32:64-S128" 7target triple = "x86_64-pc-linux-gnu" 8 9%struct = type { i64, i64 } 10 11declare zeroext i1 @return_i1() 12declare zeroext i32 @return_i32() 13declare ptr @return_i32ptr() 14declare float @return_float() 15declare %struct @return_struct() 16declare void @varargf(i32, ...) 17 18define i1 @test_i1_return() gc "statepoint-example" { 19; CHECK-LABEL: test_i1_return: 20; CHECK: # %bb.0: # %entry 21; CHECK-NEXT: pushq %rax 22; CHECK-NEXT: .cfi_def_cfa_offset 16 23; CHECK-NEXT: callq return_i1@PLT 24; CHECK-NEXT: .Ltmp0: 25; CHECK-NEXT: popq %rcx 26; CHECK-NEXT: .cfi_def_cfa_offset 8 27; CHECK-NEXT: retq 28; This is just checking that a i1 gets lowered normally when there's no extra 29; state arguments to the statepoint 30entry: 31 %safepoint_token = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(i1 ()) @return_i1, i32 0, i32 0, i32 0, i32 0) 32 %call1 = call zeroext i1 @llvm.experimental.gc.result.i1(token %safepoint_token) 33 ret i1 %call1 34} 35 36define i32 @test_i32_return() gc "statepoint-example" { 37; CHECK-LABEL: test_i32_return: 38; CHECK: # %bb.0: # %entry 39; CHECK-NEXT: pushq %rax 40; CHECK-NEXT: .cfi_def_cfa_offset 16 41; CHECK-NEXT: callq return_i32@PLT 42; CHECK-NEXT: .Ltmp1: 43; CHECK-NEXT: popq %rcx 44; CHECK-NEXT: .cfi_def_cfa_offset 8 45; CHECK-NEXT: retq 46entry: 47 %safepoint_token = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(i32 ()) @return_i32, i32 0, i32 0, i32 0, i32 0) 48 %call1 = call zeroext i32 @llvm.experimental.gc.result.i32(token %safepoint_token) 49 ret i32 %call1 50} 51 52define ptr @test_i32ptr_return() gc "statepoint-example" { 53; CHECK-LABEL: test_i32ptr_return: 54; CHECK: # %bb.0: # %entry 55; CHECK-NEXT: pushq %rax 56; CHECK-NEXT: .cfi_def_cfa_offset 16 57; CHECK-NEXT: callq return_i32ptr@PLT 58; CHECK-NEXT: .Ltmp2: 59; CHECK-NEXT: popq %rcx 60; CHECK-NEXT: .cfi_def_cfa_offset 8 61; CHECK-NEXT: retq 62entry: 63 %safepoint_token = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(ptr ()) @return_i32ptr, i32 0, i32 0, i32 0, i32 0) 64 %call1 = call ptr @llvm.experimental.gc.result.p0(token %safepoint_token) 65 ret ptr %call1 66} 67 68define float @test_float_return() gc "statepoint-example" { 69; CHECK-LABEL: test_float_return: 70; CHECK: # %bb.0: # %entry 71; CHECK-NEXT: pushq %rax 72; CHECK-NEXT: .cfi_def_cfa_offset 16 73; CHECK-NEXT: callq return_float@PLT 74; CHECK-NEXT: .Ltmp3: 75; CHECK-NEXT: popq %rax 76; CHECK-NEXT: .cfi_def_cfa_offset 8 77; CHECK-NEXT: retq 78entry: 79 %safepoint_token = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(float ()) @return_float, i32 0, i32 0, i32 0, i32 0) 80 %call1 = call float @llvm.experimental.gc.result.f32(token %safepoint_token) 81 ret float %call1 82} 83 84define %struct @test_struct_return() gc "statepoint-example" { 85; CHECK-LABEL: test_struct_return: 86; CHECK: # %bb.0: # %entry 87; CHECK-NEXT: pushq %rax 88; CHECK-NEXT: .cfi_def_cfa_offset 16 89; CHECK-NEXT: callq return_struct@PLT 90; CHECK-NEXT: .Ltmp4: 91; CHECK-NEXT: popq %rcx 92; CHECK-NEXT: .cfi_def_cfa_offset 8 93; CHECK-NEXT: retq 94entry: 95 %safepoint_token = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(%struct ()) @return_struct, i32 0, i32 0, i32 0, i32 0) 96 %call1 = call %struct @llvm.experimental.gc.result.struct(token %safepoint_token) 97 ret %struct %call1 98} 99 100define i1 @test_relocate(ptr addrspace(1) %a) gc "statepoint-example" { 101; CHECK-LABEL: test_relocate: 102; CHECK: # %bb.0: # %entry 103; CHECK-NEXT: pushq %rax 104; CHECK-NEXT: .cfi_def_cfa_offset 16 105; CHECK-NEXT: movq %rdi, (%rsp) 106; CHECK-NEXT: callq return_i1@PLT 107; CHECK-NEXT: .Ltmp5: 108; CHECK-NEXT: popq %rcx 109; CHECK-NEXT: .cfi_def_cfa_offset 8 110; CHECK-NEXT: retq 111; Check that an ununsed relocate has no code-generation impact 112entry: 113 %safepoint_token = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(i1 ()) @return_i1, i32 0, i32 0, i32 0, i32 0) ["gc-live" (ptr addrspace(1) %a)] 114 %call1 = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token, i32 0, i32 0) 115 %call2 = call zeroext i1 @llvm.experimental.gc.result.i1(token %safepoint_token) 116 ret i1 %call2 117} 118 119define void @test_void_vararg() gc "statepoint-example" { 120; CHECK-LABEL: test_void_vararg: 121; CHECK: # %bb.0: # %entry 122; CHECK-NEXT: pushq %rax 123; CHECK-NEXT: .cfi_def_cfa_offset 16 124; CHECK-NEXT: movl $42, %edi 125; CHECK-NEXT: movl $43, %esi 126; CHECK-NEXT: callq varargf@PLT 127; CHECK-NEXT: .Ltmp6: 128; CHECK-NEXT: popq %rax 129; CHECK-NEXT: .cfi_def_cfa_offset 8 130; CHECK-NEXT: retq 131; Check a statepoint wrapping a *ptr returning vararg function works 132entry: 133 %safepoint_token = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(void (i32, ...)) @varargf, i32 2, i32 0, i32 42, i32 43, i32 0, i32 0) 134 ;; if we try to use the result from a statepoint wrapping a 135 ;; non-void-returning varargf, we will experience a crash. 136 ret void 137} 138 139define i1 @test_i1_return_patchable() gc "statepoint-example" { 140; CHECK-LABEL: test_i1_return_patchable: 141; CHECK: # %bb.0: # %entry 142; CHECK-NEXT: pushq %rax 143; CHECK-NEXT: .cfi_def_cfa_offset 16 144; CHECK-NEXT: nopl (%rax) 145; CHECK-NEXT: .Ltmp7: 146; CHECK-NEXT: popq %rcx 147; CHECK-NEXT: .cfi_def_cfa_offset 8 148; CHECK-NEXT: retq 149; A patchable variant of test_i1_return 150entry: 151 %safepoint_token = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 3, ptr elementtype(i1 ()) null, i32 0, i32 0, i32 0, i32 0) 152 %call1 = call zeroext i1 @llvm.experimental.gc.result.i1(token %safepoint_token) 153 ret i1 %call1 154} 155 156declare void @consume(ptr addrspace(1) %obj) 157 158define i1 @test_cross_bb(ptr addrspace(1) %a, i1 %external_cond) gc "statepoint-example" { 159; CHECK-LABEL: test_cross_bb: 160; CHECK: # %bb.0: # %entry 161; CHECK-NEXT: pushq %rbx 162; CHECK-NEXT: .cfi_def_cfa_offset 16 163; CHECK-NEXT: subq $16, %rsp 164; CHECK-NEXT: .cfi_def_cfa_offset 32 165; CHECK-NEXT: .cfi_offset %rbx, -16 166; CHECK-NEXT: movl %esi, %ebx 167; CHECK-NEXT: movq %rdi, {{[0-9]+}}(%rsp) 168; CHECK-NEXT: callq return_i1@PLT 169; CHECK-NEXT: .Ltmp8: 170; CHECK-NEXT: testb $1, %bl 171; CHECK-NEXT: je .LBB8_2 172; CHECK-NEXT: # %bb.1: # %left 173; CHECK-NEXT: movq {{[0-9]+}}(%rsp), %rdi 174; CHECK-NEXT: movl %eax, %ebx 175; CHECK-NEXT: callq consume@PLT 176; CHECK-NEXT: movl %ebx, %eax 177; CHECK-NEXT: jmp .LBB8_3 178; CHECK-NEXT: .LBB8_2: # %right 179; CHECK-NEXT: movb $1, %al 180; CHECK-NEXT: .LBB8_3: # %right 181; CHECK-NEXT: addq $16, %rsp 182; CHECK-NEXT: .cfi_def_cfa_offset 16 183; CHECK-NEXT: popq %rbx 184; CHECK-NEXT: .cfi_def_cfa_offset 8 185; CHECK-NEXT: retq 186entry: 187 %safepoint_token = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(i1 ()) @return_i1, i32 0, i32 0, i32 0, i32 0) ["gc-live" (ptr addrspace(1) %a)] 188 br i1 %external_cond, label %left, label %right 189 190left: 191 %call1 = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token, i32 0, i32 0) 192 %call2 = call zeroext i1 @llvm.experimental.gc.result.i1(token %safepoint_token) 193 call void @consume(ptr addrspace(1) %call1) 194 ret i1 %call2 195 196right: 197 ret i1 true 198} 199 200%struct2 = type { i64, i64, i64 } 201 202declare void @consume_attributes(i32, ptr nest, i32, ptr byval(%struct2)) 203 204define void @test_attributes(ptr byval(%struct2) %s) gc "statepoint-example" { 205; CHECK-LABEL: test_attributes: 206; CHECK: # %bb.0: # %entry 207; CHECK-NEXT: pushq %rax 208; CHECK-NEXT: .cfi_def_cfa_offset 16 209; CHECK-NEXT: subq $8, %rsp 210; CHECK-NEXT: .cfi_adjust_cfa_offset 8 211; CHECK-NEXT: movq {{[0-9]+}}(%rsp), %rax 212; CHECK-NEXT: movq {{[0-9]+}}(%rsp), %rcx 213; CHECK-NEXT: movq {{[0-9]+}}(%rsp), %rdx 214; CHECK-NEXT: movl $42, %edi 215; CHECK-NEXT: xorl %r10d, %r10d 216; CHECK-NEXT: movl $17, %esi 217; CHECK-NEXT: pushq %rax 218; CHECK-NEXT: .cfi_adjust_cfa_offset 8 219; CHECK-NEXT: pushq %rdx 220; CHECK-NEXT: .cfi_adjust_cfa_offset 8 221; CHECK-NEXT: pushq %rcx 222; CHECK-NEXT: .cfi_adjust_cfa_offset 8 223; CHECK-NEXT: callq consume_attributes@PLT 224; CHECK-NEXT: .Ltmp9: 225; CHECK-NEXT: addq $32, %rsp 226; CHECK-NEXT: .cfi_adjust_cfa_offset -32 227; CHECK-NEXT: popq %rax 228; CHECK-NEXT: .cfi_def_cfa_offset 8 229; CHECK-NEXT: retq 230entry: 231; Check that arguments with attributes are lowered correctly. 232; We call a function that has a nest argument and a byval argument. 233 %statepoint_token = call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(void (i32, ptr, i32, ptr)) @consume_attributes, i32 4, i32 0, i32 42, ptr nest null, i32 17, ptr byval(%struct2) %s, i32 0, i32 0) 234 ret void 235} 236 237declare signext i1 @signext_return_i1() 238 239; Check that the generated code takes the zeroext and signext return attributes 240; on the GC result into account. The attribute in the return position allows the 241; caller to assume that the callee did the extension already. 242 243define i8 @test_signext_return(ptr) gc "statepoint-example" { 244; CHECK-LABEL: test_signext_return: 245; CHECK: # %bb.0: # %entry 246; CHECK-NEXT: pushq %rax 247; CHECK-NEXT: .cfi_def_cfa_offset 16 248; CHECK-NEXT: callq signext_return_i1@PLT 249; CHECK-NEXT: .Ltmp10: 250; CHECK-NEXT: popq %rcx 251; CHECK-NEXT: .cfi_def_cfa_offset 8 252; CHECK-NEXT: retq 253entry: 254 %safepoint_token = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(i1 ()) @signext_return_i1, i32 0, i32 0, i32 0, i32 0) 255 %call1 = call signext i1 @llvm.experimental.gc.result.i1(token %safepoint_token) 256 %ext = sext i1 %call1 to i8 257 ret i8 %ext 258} 259 260define i8 @test_zeroext_return() gc "statepoint-example" { 261; CHECK-LABEL: test_zeroext_return: 262; CHECK: # %bb.0: # %entry 263; CHECK-NEXT: pushq %rax 264; CHECK-NEXT: .cfi_def_cfa_offset 16 265; CHECK-NEXT: callq return_i1@PLT 266; CHECK-NEXT: .Ltmp11: 267; CHECK-NEXT: popq %rcx 268; CHECK-NEXT: .cfi_def_cfa_offset 8 269; CHECK-NEXT: retq 270entry: 271 %safepoint_token = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(i1 ()) @return_i1, i32 0, i32 0, i32 0, i32 0) 272 %call1 = call zeroext i1 @llvm.experimental.gc.result.i1(token %safepoint_token) 273 %ext = zext i1 %call1 to i8 274 ret i8 %ext 275} 276 277define signext i1 @test_noext_signext_return() gc "statepoint-example" { 278; CHECK-LABEL: test_noext_signext_return: 279; CHECK: # %bb.0: # %entry 280; CHECK-NEXT: pushq %rax 281; CHECK-NEXT: .cfi_def_cfa_offset 16 282; CHECK-NEXT: callq return_i1@PLT 283; CHECK-NEXT: .Ltmp12: 284; CHECK-NEXT: andb $1, %al 285; CHECK-NEXT: negb %al 286; CHECK-NEXT: popq %rcx 287; CHECK-NEXT: .cfi_def_cfa_offset 8 288; CHECK-NEXT: retq 289entry: 290 %safepoint_token = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(i1 ()) @return_i1, i32 0, i32 0, i32 0, i32 0) 291 %call1 = call i1 @llvm.experimental.gc.result.i1(token %safepoint_token) 292 ret i1 %call1 293} 294 295declare token @llvm.experimental.gc.statepoint.p0(i64, i32, ptr, i32, i32, ...) 296declare i1 @llvm.experimental.gc.result.i1(token) 297 298declare i32 @llvm.experimental.gc.result.i32(token) 299 300declare ptr @llvm.experimental.gc.result.p0(token) 301 302declare float @llvm.experimental.gc.result.f32(token) 303 304declare %struct @llvm.experimental.gc.result.struct(token) 305 306 307 308declare ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token, i32, i32) 309