|
| 1 | +; RUN: llc -O3 < %s | FileCheck %s |
| 2 | +target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" |
| 3 | +target triple = "x86_64-apple-macosx10.11.0" |
| 4 | + |
| 5 | +declare void @bar() #0 |
| 6 | +declare void @baz() |
| 7 | + |
| 8 | +define void @test1(i32 %a) gc "statepoint-example" { |
| 9 | +entry: |
| 10 | +; We expect the argument to be passed in an extra register to bar |
| 11 | +; CHECK-LABEL: test1 |
| 12 | +; CHECK: pushq %rax |
| 13 | +; CHECK-NEXT: Ltmp0: |
| 14 | +; CHECK-NEXT: .cfi_def_cfa_offset 16 |
| 15 | +; CHECK-NEXT: callq _bar |
| 16 | + %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) |
| 17 | + ret void |
| 18 | +} |
| 19 | + |
| 20 | +define void @test2(i32 %a, i32 %b) gc "statepoint-example" { |
| 21 | +entry: |
| 22 | +; Because the first call clobbers esi, we have to move the values into |
| 23 | +; new registers. Note that they stay in the registers for both calls. |
| 24 | +; CHECK-LABEL: @test2 |
| 25 | +; CHECK: movl %esi, %ebx |
| 26 | +; CHECK-NEXT: movl %edi, %ebp |
| 27 | +; CHECK-NEXT: callq _bar |
| 28 | + 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) |
| 29 | + 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) |
| 30 | + ret void |
| 31 | +} |
| 32 | + |
| 33 | +define void @test3(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, i32 %h, i32 %i) gc "statepoint-example" { |
| 34 | +entry: |
| 35 | +; TODO: We should have folded the reload into the statepoint. |
| 36 | +; CHECK-LABEL: @test3 |
| 37 | +; CHECK: movl 32(%rsp), %r10d |
| 38 | +; CHECK-NEXT: movl 24(%rsp), %r11d |
| 39 | +; CHECK-NEXT: movl 16(%rsp), %eax |
| 40 | +; CHECK-NEXT: callq _bar |
| 41 | + %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) |
| 42 | + ret void |
| 43 | +} |
| 44 | + |
| 45 | +; This case just confirms that we don't crash when given more live values |
| 46 | +; than registers. This is a case where we *have* to use a stack slot. |
| 47 | +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" { |
| 48 | +entry: |
| 49 | +; TODO: We should have folded the reload into the statepoint. |
| 50 | +; CHECK-LABEL: test4 |
| 51 | +; CHECK: pushq %r15 |
| 52 | +; CHECK: pushq %r14 |
| 53 | +; CHECK: pushq %r13 |
| 54 | +; CHECK: pushq %r12 |
| 55 | +; CHECK: pushq %rbx |
| 56 | +; CHECK: pushq %rax |
| 57 | +; CHECK: movl 128(%rsp), %r13d |
| 58 | +; CHECK-NEXT: movl 120(%rsp), %r12d |
| 59 | +; CHECK-NEXT: movl 112(%rsp), %r15d |
| 60 | +; CHECK-NEXT: movl 104(%rsp), %r14d |
| 61 | +; CHECK-NEXT: movl 96(%rsp), %ebp |
| 62 | +; CHECK-NEXT: movl 88(%rsp), %ebx |
| 63 | +; CHECK-NEXT: movl 80(%rsp), %r11d |
| 64 | +; CHECK-NEXT: movl 72(%rsp), %r10d |
| 65 | +; CHECK-NEXT: movl 64(%rsp), %eax |
| 66 | +; CHECK-NEXT: callq _bar |
| 67 | + %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) |
| 68 | + ret void |
| 69 | +} |
| 70 | + |
| 71 | +; A live-through gc-value must be spilled even if it is also a live-in deopt |
| 72 | +; value. For live-in, we could technically report the register copy, but from |
| 73 | +; a code quality perspective it's better to reuse the required stack slot so |
| 74 | +; as to put less stress on the register allocator for no benefit. |
| 75 | +define i32 addrspace(1)* @test5(i32 %a, i32 addrspace(1)* %p) gc "statepoint-example" { |
| 76 | +entry: |
| 77 | +; CHECK-LABEL: test5 |
| 78 | +; CHECK: movq %rsi, (%rsp) |
| 79 | +; CHECK-NEXT: callq _bar |
| 80 | + %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) |
| 81 | + %p2 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %token, i32 9, i32 9) |
| 82 | + ret i32 addrspace(1)* %p2 |
| 83 | +} |
| 84 | + |
| 85 | +; Show the interaction of live-through spilling followed by live-in. |
| 86 | +define void @test6(i32 %a) gc "statepoint-example" { |
| 87 | +entry: |
| 88 | +; TODO: We could have reused the previous spill slot at zero additional cost. |
| 89 | +; CHECK-LABEL: test6 |
| 90 | +; CHECK: movl %edi, %ebx |
| 91 | +; CHECK: movl %ebx, 12(%rsp) |
| 92 | +; CHECK-NEXT: callq _baz |
| 93 | +; CHECK-NEXT: Ltmp30: |
| 94 | +; CHECK-NEXT: callq _bar |
| 95 | + 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) |
| 96 | + 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) |
| 97 | + ret void |
| 98 | +} |
| 99 | + |
| 100 | + |
| 101 | +; CHECK: Ltmp1-_test1 |
| 102 | +; CHECK: .byte 1 |
| 103 | +; CHECK-NEXT: .byte 4 |
| 104 | +; CHECK-NEXT: .short 5 |
| 105 | +; CHECK-NEXT: .long 0 |
| 106 | + |
| 107 | +; CHECK: Ltmp7-_test2 |
| 108 | +; CHECK: .byte 1 |
| 109 | +; CHECK-NEXT: .byte 4 |
| 110 | +; CHECK-NEXT: .short 6 |
| 111 | +; CHECK-NEXT: .long 0 |
| 112 | +; CHECK: .byte 1 |
| 113 | +; CHECK-NEXT: .byte 4 |
| 114 | +; CHECK-NEXT: .short 3 |
| 115 | +; CHECK-NEXT: .long 0 |
| 116 | +; CHECK: Ltmp8-_test2 |
| 117 | +; CHECK: .byte 1 |
| 118 | +; CHECK-NEXT: .byte 4 |
| 119 | +; CHECK-NEXT: .short 3 |
| 120 | +; CHECK-NEXT: .long 0 |
| 121 | +; CHECK: .byte 1 |
| 122 | +; CHECK-NEXT: .byte 4 |
| 123 | +; CHECK-NEXT: .short 6 |
| 124 | +; CHECK-NEXT: .long 0 |
| 125 | + |
| 126 | +declare token @llvm.experimental.gc.statepoint.p0f_isVoidf(i64, i32, void ()*, i32, i32, ...) |
| 127 | +declare i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token, i32, i32) |
| 128 | + |
| 129 | + |
| 130 | +attributes #0 = { "deopt-lowering"="live-in" } |
| 131 | +attributes #1 = { "deopt-lowering"="live-through" } |
0 commit comments