1 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 2 ; RUN: llc -verify-machineinstrs -O3 < %s | FileCheck %s 3 target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" 4 target triple = "x86_64-apple-macosx10.11.0" 5 6 declare void @bar() #0 7 declare void @baz() 8 9 define void @test1(i32 %a) gc "statepoint-example" { 10 ; CHECK-LABEL: test1: 11 ; CHECK: ## %bb.0: ## %entry 12 ; CHECK-NEXT: pushq %rax 13 ; CHECK-NEXT: .cfi_def_cfa_offset 16 14 ; CHECK-NEXT: callq _bar 15 ; CHECK-NEXT: Ltmp0: 16 ; CHECK-NEXT: popq %rax 17 ; CHECK-NEXT: retq 18 entry: 19 ; We expect the argument to be passed in an extra register to bar 20 %statepoint_token1 = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 2882400000, i32 0, void ()* @bar, i32 0, i32 2, i32 0, i32 1, i32 %a) 21 ret void 22 } 23 24 define void @test2(i32 %a, i32 %b) gc "statepoint-example" { 25 ; CHECK-LABEL: test2: 26 ; CHECK: ## %bb.0: ## %entry 27 ; CHECK-NEXT: pushq %rbp 28 ; CHECK-NEXT: .cfi_def_cfa_offset 16 29 ; CHECK-NEXT: pushq %rbx 30 ; CHECK-NEXT: .cfi_def_cfa_offset 24 31 ; CHECK-NEXT: pushq %rax 32 ; CHECK-NEXT: .cfi_def_cfa_offset 32 33 ; CHECK-NEXT: .cfi_offset %rbx, -24 34 ; CHECK-NEXT: .cfi_offset %rbp, -16 35 ; CHECK-NEXT: movl %esi, %ebx 36 ; CHECK-NEXT: movl %edi, %ebp 37 ; CHECK-NEXT: callq _bar 38 ; CHECK-NEXT: Ltmp1: 39 ; CHECK-NEXT: callq _bar 40 ; CHECK-NEXT: Ltmp2: 41 ; CHECK-NEXT: addq $8, %rsp 42 ; CHECK-NEXT: popq %rbx 43 ; CHECK-NEXT: popq %rbp 44 ; CHECK-NEXT: retq 45 entry: 46 ; Because the first call clobbers esi, we have to move the values into 47 ; new registers. Note that they stay in the registers for both calls. 48 call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 2882400000, i32 0, void ()* @bar, i32 0, i32 2, i32 0, i32 2, i32 %a, i32 %b) 49 call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 2882400000, i32 0, void ()* @bar, i32 0, i32 2, i32 0, i32 2, i32 %b, i32 %a) 50 ret void 51 } 52 53 define void @test3(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, i32 %h, i32 %i) gc "statepoint-example" { 54 ; CHECK-LABEL: test3: 55 ; CHECK: ## %bb.0: ## %entry 56 ; CHECK-NEXT: pushq %rax 57 ; CHECK-NEXT: .cfi_def_cfa_offset 16 58 ; CHECK-NEXT: callq _bar 59 ; CHECK-NEXT: Ltmp3: 60 ; CHECK-NEXT: popq %rax 61 ; CHECK-NEXT: retq 62 entry: 63 ; We directly reference the argument slot 64 %statepoint_token1 = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 2882400000, i32 0, void ()* @bar, i32 0, i32 2, i32 0, i32 9, i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, i32 %h, i32 %i) 65 ret void 66 } 67 68 ; This case just confirms that we don't crash when given more live values 69 ; than registers. This is a case where we *have* to use a stack slot. This 70 ; also ends up being a good test of whether we can fold loads from immutable 71 ; stack slots into the statepoint. 72 define void @test4(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, i32 %h, i32 %i, i32 %j, i32 %k, i32 %l, i32 %m, i32 %n, i32 %o, i32 %p, i32 %q, i32 %r, i32 %s, i32 %t, i32 %u, i32 %v, i32 %w, i32 %x, i32 %y, i32 %z) gc "statepoint-example" { 73 ; CHECK-LABEL: test4: 74 ; CHECK: ## %bb.0: ## %entry 75 ; CHECK-NEXT: pushq %rax 76 ; CHECK-NEXT: .cfi_def_cfa_offset 16 77 ; CHECK-NEXT: callq _bar 78 ; CHECK-NEXT: Ltmp4: 79 ; CHECK-NEXT: popq %rax 80 ; CHECK-NEXT: retq 81 entry: 82 %statepoint_token1 = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 2882400000, i32 0, void ()* @bar, i32 0, i32 2, i32 0, i32 26, i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, i32 %h, i32 %i, i32 %j, i32 %k, i32 %l, i32 %m, i32 %n, i32 %o, i32 %p, i32 %q, i32 %r, i32 %s, i32 %t, i32 %u, i32 %v, i32 %w, i32 %x, i32 %y, i32 %z) 83 ret void 84 } 85 86 ; A live-through gc-value must be spilled even if it is also a live-in deopt 87 ; value. For live-in, we could technically report the register copy, but from 88 ; a code quality perspective it's better to reuse the required stack slot so 89 ; as to put less stress on the register allocator for no benefit. 90 define i32 addrspace(1)* @test5(i32 %a, i32 addrspace(1)* %p) gc "statepoint-example" { 91 ; CHECK-LABEL: test5: 92 ; CHECK: ## %bb.0: ## %entry 93 ; CHECK-NEXT: pushq %rax 94 ; CHECK-NEXT: .cfi_def_cfa_offset 16 95 ; CHECK-NEXT: movq %rsi, (%rsp) 96 ; CHECK-NEXT: callq _bar 97 ; CHECK-NEXT: Ltmp5: 98 ; CHECK-NEXT: movq (%rsp), %rax 99 ; CHECK-NEXT: popq %rcx 100 ; CHECK-NEXT: retq 101 entry: 102 %token = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 2882400000, i32 0, void ()* @bar, i32 0, i32 2, i32 0, i32 1, i32 %a, i32 addrspace(1)* %p, i32 addrspace(1)* %p) 103 %p2 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %token, i32 9, i32 9) 104 ret i32 addrspace(1)* %p2 105 } 106 107 ; Show the interaction of live-through spilling followed by live-in. 108 define void @test6(i32 %a) gc "statepoint-example" { 109 ; CHECK-LABEL: test6: 110 ; CHECK: ## %bb.0: ## %entry 111 ; CHECK-NEXT: pushq %rbx 112 ; CHECK-NEXT: .cfi_def_cfa_offset 16 113 ; CHECK-NEXT: subq $16, %rsp 114 ; CHECK-NEXT: .cfi_def_cfa_offset 32 115 ; CHECK-NEXT: .cfi_offset %rbx, -16 116 ; CHECK-NEXT: movl %edi, %ebx 117 ; CHECK-NEXT: movl %edi, {{[0-9]+}}(%rsp) 118 ; CHECK-NEXT: callq _baz 119 ; CHECK-NEXT: Ltmp6: 120 ; CHECK-NEXT: callq _bar 121 ; CHECK-NEXT: Ltmp7: 122 ; CHECK-NEXT: addq $16, %rsp 123 ; CHECK-NEXT: popq %rbx 124 ; CHECK-NEXT: retq 125 entry: 126 call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 2882400000, i32 0, void ()* @baz, i32 0, i32 0, i32 0, i32 1, i32 %a) 127 call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 2882400000, i32 0, void ()* @bar, i32 0, i32 2, i32 0, i32 1, i32 %a) 128 ret void 129 } 130 131 132 ; CHECK: Ltmp0-_test1 133 ; CHECK: .byte 1 134 ; CHECK-NEXT: .byte 0 135 ; CHECK-NEXT: .short 4 136 ; CHECK-NEXT: .short 5 137 ; CHECK-NEXT: .short 0 138 ; CHECK-NEXT: .long 0 139 140 ; CHECK: Ltmp1-_test2 141 ; CHECK: .byte 1 142 ; CHECK-NEXT: .byte 0 143 ; CHECK-NEXT: .short 4 144 ; CHECK-NEXT: .short 6 145 ; CHECK-NEXT: .short 0 146 ; CHECK-NEXT: .long 0 147 ; CHECK: .byte 1 148 ; CHECK-NEXT: .byte 0 149 ; CHECK-NEXT: .short 4 150 ; CHECK-NEXT: .short 3 151 ; CHECK-NEXT: .short 0 152 ; CHECK-NEXT: .long 0 153 ; CHECK: Ltmp2-_test2 154 ; CHECK: .byte 1 155 ; CHECK-NEXT: .byte 0 156 ; CHECK-NEXT: .short 4 157 ; CHECK-NEXT: .short 3 158 ; CHECK-NEXT: .short 0 159 ; CHECK-NEXT: .long 0 160 ; CHECK: .byte 1 161 ; CHECK-NEXT: .byte 0 162 ; CHECK-NEXT: .short 4 163 ; CHECK-NEXT: .short 6 164 ; CHECK-NEXT: .short 0 165 ; CHECK-NEXT: .long 0 166 167 declare token @llvm.experimental.gc.statepoint.p0f_isVoidf(i64, i32, void ()*, i32, i32, ...) 168 declare i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token, i32, i32) 169 170 171 attributes #0 = { "deopt-lowering"="live-in" } 172 attributes #1 = { "deopt-lowering"="live-through" } 173