| ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py |
| ; RUN: llc -max-registers-for-gc-values=4 -fixup-allow-gcptr-in-csr=true < %s | FileCheck %s |
| |
| target datalayout = "e-i64:64-f80:128-n8:16:32:64-S128" |
| target triple = "x86_64-pc-linux-gnu" |
| |
| declare i1 @return_i1() |
| declare void @func() |
| declare void @consume(i32 addrspace(1)*) |
| declare i32 @consume1(i32) gc "statepoint-example" |
| declare void @consume2(i32 addrspace(1)*, i32 addrspace(1)*) |
| declare void @consume3(float) gc "statepoint-example" |
| declare float @consume4(i64) gc "statepoint-example" |
| declare void @consume5(i32 addrspace(1)*, i32 addrspace(1)*, i32 addrspace(1)*, i32 addrspace(1)*, i32 addrspace(1)*) |
| |
| declare void @use1(i32 addrspace(1)*, i8 addrspace(1)*) |
| |
| ; test most simple relocate |
| define i1 @test_relocate(i32 addrspace(1)* %a) gc "statepoint-example" { |
| ; CHECK-LABEL: test_relocate: |
| ; CHECK: # %bb.0: # %entry |
| ; CHECK-NEXT: pushq %rbp |
| ; CHECK-NEXT: .cfi_def_cfa_offset 16 |
| ; CHECK-NEXT: pushq %rbx |
| ; CHECK-NEXT: .cfi_def_cfa_offset 24 |
| ; CHECK-NEXT: pushq %rax |
| ; CHECK-NEXT: .cfi_def_cfa_offset 32 |
| ; CHECK-NEXT: .cfi_offset %rbx, -24 |
| ; CHECK-NEXT: .cfi_offset %rbp, -16 |
| ; CHECK-NEXT: movq %rdi, %rbx |
| ; CHECK-NEXT: callq return_i1@PLT |
| ; CHECK-NEXT: .Ltmp0: |
| ; CHECK-NEXT: movl %eax, %ebp |
| ; CHECK-NEXT: movq %rbx, %rdi |
| ; CHECK-NEXT: callq consume@PLT |
| ; CHECK-NEXT: movl %ebp, %eax |
| ; CHECK-NEXT: addq $8, %rsp |
| ; CHECK-NEXT: .cfi_def_cfa_offset 24 |
| ; CHECK-NEXT: popq %rbx |
| ; CHECK-NEXT: .cfi_def_cfa_offset 16 |
| ; CHECK-NEXT: popq %rbp |
| ; CHECK-NEXT: .cfi_def_cfa_offset 8 |
| ; CHECK-NEXT: retq |
| entry: |
| %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 0) ["gc-live" (i32 addrspace(1)* %a)] |
| %rel1 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 0, i32 0) |
| %res1 = call zeroext i1 @llvm.experimental.gc.result.i1(token %safepoint_token) |
| call void @consume(i32 addrspace(1)* %rel1) |
| ret i1 %res1 |
| } |
| |
| ; test pointer variables intermixed with pointer constants |
| define void @test_mixed(i32 addrspace(1)* %a, i32 addrspace(1)* %b, i32 addrspace(1)* %c) gc "statepoint-example" { |
| ; CHECK-LABEL: test_mixed: |
| ; CHECK: # %bb.0: # %entry |
| ; CHECK-NEXT: pushq %r15 |
| ; CHECK-NEXT: .cfi_def_cfa_offset 16 |
| ; CHECK-NEXT: pushq %r14 |
| ; CHECK-NEXT: .cfi_def_cfa_offset 24 |
| ; CHECK-NEXT: pushq %rbx |
| ; CHECK-NEXT: .cfi_def_cfa_offset 32 |
| ; CHECK-NEXT: .cfi_offset %rbx, -32 |
| ; CHECK-NEXT: .cfi_offset %r14, -24 |
| ; CHECK-NEXT: .cfi_offset %r15, -16 |
| ; CHECK-NEXT: movq %rdx, %r14 |
| ; CHECK-NEXT: movq %rsi, %r15 |
| ; CHECK-NEXT: movq %rdi, %rbx |
| ; CHECK-NEXT: callq func@PLT |
| ; CHECK-NEXT: .Ltmp1: |
| ; CHECK-NEXT: movq %rbx, %rdi |
| ; CHECK-NEXT: xorl %esi, %esi |
| ; CHECK-NEXT: movq %r15, %rdx |
| ; CHECK-NEXT: xorl %ecx, %ecx |
| ; CHECK-NEXT: movq %r14, %r8 |
| ; CHECK-NEXT: callq consume5@PLT |
| ; CHECK-NEXT: popq %rbx |
| ; CHECK-NEXT: .cfi_def_cfa_offset 24 |
| ; CHECK-NEXT: popq %r14 |
| ; CHECK-NEXT: .cfi_def_cfa_offset 16 |
| ; CHECK-NEXT: popq %r15 |
| ; CHECK-NEXT: .cfi_def_cfa_offset 8 |
| ; CHECK-NEXT: retq |
| entry: |
| %safepoint_token = tail call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0) ["gc-live" (i32 addrspace(1)* %a, i32 addrspace(1)* null, i32 addrspace(1)* %b, i32 addrspace(1)* null, i32 addrspace(1)* %c)] |
| %rel1 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 0, i32 0) |
| %rel2 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 1, i32 1) |
| %rel3 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 2, i32 2) |
| %rel4 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 3, i32 3) |
| %rel5 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 4, i32 4) |
| call void @consume5(i32 addrspace(1)* %rel1, i32 addrspace(1)* %rel2, i32 addrspace(1)* %rel3, i32 addrspace(1)* %rel4, i32 addrspace(1)* %rel5) |
| ret void |
| } |
| |
| ; same as above, but for alloca |
| define i32 addrspace(1)* @test_alloca(i32 addrspace(1)* %ptr) gc "statepoint-example" { |
| ; CHECK-LABEL: test_alloca: |
| ; CHECK: # %bb.0: # %entry |
| ; CHECK-NEXT: pushq %r14 |
| ; CHECK-NEXT: .cfi_def_cfa_offset 16 |
| ; CHECK-NEXT: pushq %rbx |
| ; CHECK-NEXT: .cfi_def_cfa_offset 24 |
| ; CHECK-NEXT: pushq %rax |
| ; CHECK-NEXT: .cfi_def_cfa_offset 32 |
| ; CHECK-NEXT: .cfi_offset %rbx, -24 |
| ; CHECK-NEXT: .cfi_offset %r14, -16 |
| ; CHECK-NEXT: movq %rdi, %rbx |
| ; CHECK-NEXT: movq %rdi, (%rsp) |
| ; CHECK-NEXT: callq return_i1@PLT |
| ; CHECK-NEXT: .Ltmp2: |
| ; CHECK-NEXT: movq (%rsp), %r14 |
| ; CHECK-NEXT: movq %rbx, %rdi |
| ; CHECK-NEXT: callq consume@PLT |
| ; CHECK-NEXT: movq %r14, %rax |
| ; CHECK-NEXT: addq $8, %rsp |
| ; CHECK-NEXT: .cfi_def_cfa_offset 24 |
| ; CHECK-NEXT: popq %rbx |
| ; CHECK-NEXT: .cfi_def_cfa_offset 16 |
| ; CHECK-NEXT: popq %r14 |
| ; CHECK-NEXT: .cfi_def_cfa_offset 8 |
| ; CHECK-NEXT: retq |
| entry: |
| %alloca = alloca i32 addrspace(1)*, align 8 |
| store i32 addrspace(1)* %ptr, i32 addrspace(1)** %alloca |
| %safepoint_token = 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 0) ["gc-live" (i32 addrspace(1)** %alloca, i32 addrspace(1)* %ptr)] |
| %rel1 = load i32 addrspace(1)*, i32 addrspace(1)** %alloca |
| %rel2 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 1, i32 1) |
| call void @consume(i32 addrspace(1)* %rel2) |
| ret i32 addrspace(1)* %rel1 |
| } |
| |
| ; test base != derived |
| define void @test_base_derived(i32 addrspace(1)* %base, i32 addrspace(1)* %derived) gc "statepoint-example" { |
| ; CHECK-LABEL: test_base_derived: |
| ; CHECK: # %bb.0: |
| ; CHECK-NEXT: pushq %r14 |
| ; CHECK-NEXT: .cfi_def_cfa_offset 16 |
| ; CHECK-NEXT: pushq %rbx |
| ; CHECK-NEXT: .cfi_def_cfa_offset 24 |
| ; CHECK-NEXT: pushq %rax |
| ; CHECK-NEXT: .cfi_def_cfa_offset 32 |
| ; CHECK-NEXT: .cfi_offset %rbx, -24 |
| ; CHECK-NEXT: .cfi_offset %r14, -16 |
| ; CHECK-NEXT: movq %rsi, %rbx |
| ; CHECK-NEXT: movq %rdi, %r14 |
| ; CHECK-NEXT: callq func@PLT |
| ; CHECK-NEXT: .Ltmp3: |
| ; CHECK-NEXT: movq %rbx, %rdi |
| ; CHECK-NEXT: callq consume@PLT |
| ; CHECK-NEXT: addq $8, %rsp |
| ; CHECK-NEXT: .cfi_def_cfa_offset 24 |
| ; CHECK-NEXT: popq %rbx |
| ; CHECK-NEXT: .cfi_def_cfa_offset 16 |
| ; CHECK-NEXT: popq %r14 |
| ; CHECK-NEXT: .cfi_def_cfa_offset 8 |
| ; CHECK-NEXT: retq |
| %safepoint_token = tail call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0) ["gc-live" (i32 addrspace(1)* %base, i32 addrspace(1)* %derived)] |
| %reloc = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 0, i32 1) |
| call void @consume(i32 addrspace(1)* %reloc) |
| ret void |
| } |
| |
| ; deopt GC pointer not present in GC args goes on reg. |
| define void @test_deopt_gcpointer(i32 addrspace(1)* %a, i32 addrspace(1)* %b) gc "statepoint-example" { |
| ; CHECK-LABEL: test_deopt_gcpointer: |
| ; CHECK: # %bb.0: |
| ; CHECK-NEXT: pushq %r14 |
| ; CHECK-NEXT: .cfi_def_cfa_offset 16 |
| ; CHECK-NEXT: pushq %rbx |
| ; CHECK-NEXT: .cfi_def_cfa_offset 24 |
| ; CHECK-NEXT: pushq %rax |
| ; CHECK-NEXT: .cfi_def_cfa_offset 32 |
| ; CHECK-NEXT: .cfi_offset %rbx, -24 |
| ; CHECK-NEXT: .cfi_offset %r14, -16 |
| ; CHECK-NEXT: movq %rsi, %rbx |
| ; CHECK-NEXT: movq %rdi, %r14 |
| ; CHECK-NEXT: callq func@PLT |
| ; CHECK-NEXT: .Ltmp4: |
| ; CHECK-NEXT: movq %rbx, %rdi |
| ; CHECK-NEXT: callq consume@PLT |
| ; CHECK-NEXT: addq $8, %rsp |
| ; CHECK-NEXT: .cfi_def_cfa_offset 24 |
| ; CHECK-NEXT: popq %rbx |
| ; CHECK-NEXT: .cfi_def_cfa_offset 16 |
| ; CHECK-NEXT: popq %r14 |
| ; CHECK-NEXT: .cfi_def_cfa_offset 8 |
| ; CHECK-NEXT: retq |
| %safepoint_token = tail call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0) ["deopt" (i32 addrspace(1)* %a), "gc-live" (i32 addrspace(1)* %b)] |
| %rel = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 0, i32 0) |
| call void @consume(i32 addrspace(1)* %rel) |
| ret void |
| } |
| |
| ;; Two gc.relocates of the same input, should require only a single spill/fill |
| define void @test_gcrelocate_uniqueing(i32 addrspace(1)* %ptr) gc "statepoint-example" { |
| ; CHECK-LABEL: test_gcrelocate_uniqueing: |
| ; CHECK: # %bb.0: |
| ; CHECK-NEXT: pushq %rbx |
| ; CHECK-NEXT: .cfi_def_cfa_offset 16 |
| ; CHECK-NEXT: .cfi_offset %rbx, -16 |
| ; CHECK-NEXT: movq %rdi, %rbx |
| ; CHECK-NEXT: callq func@PLT |
| ; CHECK-NEXT: .Ltmp5: |
| ; CHECK-NEXT: movq %rbx, %rdi |
| ; CHECK-NEXT: movq %rbx, %rsi |
| ; CHECK-NEXT: callq consume2@PLT |
| ; CHECK-NEXT: popq %rbx |
| ; CHECK-NEXT: .cfi_def_cfa_offset 8 |
| ; CHECK-NEXT: retq |
| %tok = tail call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0) ["deopt" (i32 addrspace(1)* %ptr, i32 undef), "gc-live" (i32 addrspace(1)* %ptr, i32 addrspace(1)* %ptr)] |
| %a = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %tok, i32 0, i32 0) |
| %b = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %tok, i32 1, i32 1) |
| call void @consume2(i32 addrspace(1)* %a, i32 addrspace(1)* %b) |
| ret void |
| } |
| |
| ; Two gc.relocates of a bitcasted pointer should only require a single spill/fill |
| define void @test_gcptr_uniqueing(i32 addrspace(1)* %ptr) gc "statepoint-example" { |
| ; CHECK-LABEL: test_gcptr_uniqueing: |
| ; CHECK: # %bb.0: |
| ; CHECK-NEXT: pushq %rbx |
| ; CHECK-NEXT: .cfi_def_cfa_offset 16 |
| ; CHECK-NEXT: .cfi_offset %rbx, -16 |
| ; CHECK-NEXT: movq %rdi, %rbx |
| ; CHECK-NEXT: callq func@PLT |
| ; CHECK-NEXT: .Ltmp6: |
| ; CHECK-NEXT: movq %rbx, %rdi |
| ; CHECK-NEXT: movq %rbx, %rsi |
| ; CHECK-NEXT: callq use1@PLT |
| ; CHECK-NEXT: popq %rbx |
| ; CHECK-NEXT: .cfi_def_cfa_offset 8 |
| ; CHECK-NEXT: retq |
| %ptr2 = bitcast i32 addrspace(1)* %ptr to i8 addrspace(1)* |
| %tok = tail call token (i64, i32, void ()*, i32, i32, ...) |
| @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0) ["deopt" (i32 addrspace(1)* %ptr, i32 undef), "gc-live" (i32 addrspace(1)* %ptr, i8 addrspace(1)* %ptr2)] |
| %a = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %tok, i32 0, i32 0) |
| %b = call i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token %tok, i32 1, i32 1) |
| call void @use1(i32 addrspace(1)* %a, i8 addrspace(1)* %b) |
| ret void |
| } |
| |
| ; |
| ; Cross-basicblock relocates are handled with spilling for now. |
| define i1 @test_cross_bb(i32 addrspace(1)* %a, i1 %external_cond) gc "statepoint-example" { |
| ; CHECK-LABEL: test_cross_bb: |
| ; CHECK: # %bb.0: # %entry |
| ; CHECK-NEXT: pushq %rbp |
| ; CHECK-NEXT: .cfi_def_cfa_offset 16 |
| ; CHECK-NEXT: pushq %r14 |
| ; CHECK-NEXT: .cfi_def_cfa_offset 24 |
| ; CHECK-NEXT: pushq %rbx |
| ; CHECK-NEXT: .cfi_def_cfa_offset 32 |
| ; CHECK-NEXT: .cfi_offset %rbx, -32 |
| ; CHECK-NEXT: .cfi_offset %r14, -24 |
| ; CHECK-NEXT: .cfi_offset %rbp, -16 |
| ; CHECK-NEXT: movl %esi, %ebp |
| ; CHECK-NEXT: movq %rdi, %rbx |
| ; CHECK-NEXT: callq return_i1@PLT |
| ; CHECK-NEXT: .Ltmp7: |
| ; CHECK-NEXT: testb $1, %bpl |
| ; CHECK-NEXT: je .LBB7_2 |
| ; CHECK-NEXT: # %bb.1: # %left |
| ; CHECK-NEXT: movl %eax, %r14d |
| ; CHECK-NEXT: movq %rbx, %rdi |
| ; CHECK-NEXT: callq consume@PLT |
| ; CHECK-NEXT: movl %r14d, %eax |
| ; CHECK-NEXT: jmp .LBB7_3 |
| ; CHECK-NEXT: .LBB7_2: # %right |
| ; CHECK-NEXT: movb $1, %al |
| ; CHECK-NEXT: .LBB7_3: # %right |
| ; CHECK-NEXT: popq %rbx |
| ; CHECK-NEXT: .cfi_def_cfa_offset 24 |
| ; CHECK-NEXT: popq %r14 |
| ; CHECK-NEXT: .cfi_def_cfa_offset 16 |
| ; CHECK-NEXT: popq %rbp |
| ; CHECK-NEXT: .cfi_def_cfa_offset 8 |
| ; CHECK-NEXT: retq |
| entry: |
| %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 0) ["gc-live" (i32 addrspace(1)* %a)] |
| br i1 %external_cond, label %left, label %right |
| |
| left: |
| %call1 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 0, i32 0) |
| %call2 = call zeroext i1 @llvm.experimental.gc.result.i1(token %safepoint_token) |
| call void @consume(i32 addrspace(1)* %call1) |
| ret i1 %call2 |
| |
| right: |
| ret i1 true |
| } |
| |
| ; No need to check post-regalloc output as it is the same |
| define i1 @duplicate_reloc() gc "statepoint-example" { |
| ; CHECK-LABEL: duplicate_reloc: |
| ; CHECK: # %bb.0: # %entry |
| ; CHECK-NEXT: pushq %rax |
| ; CHECK-NEXT: .cfi_def_cfa_offset 16 |
| ; CHECK-NEXT: callq func@PLT |
| ; CHECK-NEXT: .Ltmp8: |
| ; CHECK-NEXT: callq func@PLT |
| ; CHECK-NEXT: .Ltmp9: |
| ; CHECK-NEXT: movb $1, %al |
| ; CHECK-NEXT: popq %rcx |
| ; CHECK-NEXT: .cfi_def_cfa_offset 8 |
| ; CHECK-NEXT: retq |
| entry: |
| %safepoint_token = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0) ["gc-live" (i32 addrspace(1)* null, i32 addrspace(1)* null)] |
| %base = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 0, i32 0) |
| %derived = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 0, i32 1) |
| %safepoint_token2 = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0) ["gc-live" (i32 addrspace(1)* %base, i32 addrspace(1)* %derived)] |
| %base_reloc = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token2, i32 0, i32 0) |
| %derived_reloc = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token2, i32 0, i32 1) |
| %cmp1 = icmp eq i32 addrspace(1)* %base_reloc, null |
| %cmp2 = icmp eq i32 addrspace(1)* %derived_reloc, null |
| %cmp = and i1 %cmp1, %cmp2 |
| ret i1 %cmp |
| } |
| |
| ; Vectors cannot go in VRegs |
| ; No need to check post-regalloc output as it is lowered using old scheme |
| define <2 x i8 addrspace(1)*> @test_vector(<2 x i8 addrspace(1)*> %obj) gc "statepoint-example" { |
| ; CHECK-LABEL: test_vector: |
| ; CHECK: # %bb.0: # %entry |
| ; CHECK-NEXT: subq $24, %rsp |
| ; CHECK-NEXT: .cfi_def_cfa_offset 32 |
| ; CHECK-NEXT: movaps %xmm0, (%rsp) |
| ; CHECK-NEXT: callq func@PLT |
| ; CHECK-NEXT: .Ltmp10: |
| ; CHECK-NEXT: movaps (%rsp), %xmm0 |
| ; CHECK-NEXT: addq $24, %rsp |
| ; CHECK-NEXT: .cfi_def_cfa_offset 8 |
| ; CHECK-NEXT: retq |
| entry: |
| %safepoint_token = call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0) ["gc-live" (<2 x i8 addrspace(1)*> %obj)] |
| %obj.relocated = call coldcc <2 x i8 addrspace(1)*> @llvm.experimental.gc.relocate.v2p1i8(token %safepoint_token, i32 0, i32 0) ; (%obj, %obj) |
| ret <2 x i8 addrspace(1)*> %obj.relocated |
| } |
| |
| |
| ; test limit on amount of vregs |
| define void @test_limit(i32 addrspace(1)* %a, i32 addrspace(1)* %b, i32 addrspace(1)* %c, i32 addrspace(1)* %d, i32 addrspace(1)* %e) gc "statepoint-example" { |
| ; CHECK-LABEL: test_limit: |
| ; CHECK: # %bb.0: # %entry |
| ; CHECK-NEXT: pushq %r15 |
| ; CHECK-NEXT: .cfi_def_cfa_offset 16 |
| ; CHECK-NEXT: pushq %r14 |
| ; CHECK-NEXT: .cfi_def_cfa_offset 24 |
| ; CHECK-NEXT: pushq %r12 |
| ; CHECK-NEXT: .cfi_def_cfa_offset 32 |
| ; CHECK-NEXT: pushq %rbx |
| ; CHECK-NEXT: .cfi_def_cfa_offset 40 |
| ; CHECK-NEXT: pushq %rax |
| ; CHECK-NEXT: .cfi_def_cfa_offset 48 |
| ; CHECK-NEXT: .cfi_offset %rbx, -40 |
| ; CHECK-NEXT: .cfi_offset %r12, -32 |
| ; CHECK-NEXT: .cfi_offset %r14, -24 |
| ; CHECK-NEXT: .cfi_offset %r15, -16 |
| ; CHECK-NEXT: movq %r8, %r14 |
| ; CHECK-NEXT: movq %rcx, %r15 |
| ; CHECK-NEXT: movq %rdx, %r12 |
| ; CHECK-NEXT: movq %rsi, %rbx |
| ; CHECK-NEXT: movq %rdi, (%rsp) |
| ; CHECK-NEXT: callq func@PLT |
| ; CHECK-NEXT: .Ltmp11: |
| ; CHECK-NEXT: movq (%rsp), %rdi |
| ; CHECK-NEXT: movq %rbx, %rsi |
| ; CHECK-NEXT: movq %r12, %rdx |
| ; CHECK-NEXT: movq %r15, %rcx |
| ; CHECK-NEXT: movq %r14, %r8 |
| ; CHECK-NEXT: callq consume5@PLT |
| ; CHECK-NEXT: addq $8, %rsp |
| ; CHECK-NEXT: .cfi_def_cfa_offset 40 |
| ; CHECK-NEXT: popq %rbx |
| ; CHECK-NEXT: .cfi_def_cfa_offset 32 |
| ; CHECK-NEXT: popq %r12 |
| ; CHECK-NEXT: .cfi_def_cfa_offset 24 |
| ; CHECK-NEXT: popq %r14 |
| ; CHECK-NEXT: .cfi_def_cfa_offset 16 |
| ; CHECK-NEXT: popq %r15 |
| ; CHECK-NEXT: .cfi_def_cfa_offset 8 |
| ; CHECK-NEXT: retq |
| entry: |
| %safepoint_token = tail call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0) ["gc-live" (i32 addrspace(1)* %a, i32 addrspace(1)* %b, i32 addrspace(1)* %c, i32 addrspace(1)* %d, i32 addrspace(1)* %e)] |
| %rel1 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 0, i32 0) |
| %rel2 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 1, i32 1) |
| %rel3 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 2, i32 2) |
| %rel4 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 3, i32 3) |
| %rel5 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 4, i32 4) |
| call void @consume5(i32 addrspace(1)* %rel1, i32 addrspace(1)* %rel2, i32 addrspace(1)* %rel3, i32 addrspace(1)* %rel4, i32 addrspace(1)* %rel5) |
| ret void |
| } |
| |
| ; test ISEL for constant base pointer - must properly tie operands |
| define void @test_const_base(i32 addrspace(1)* %a) gc "statepoint-example" { |
| ; CHECK-LABEL: test_const_base: |
| ; CHECK: # %bb.0: # %entry |
| ; CHECK-NEXT: pushq %rbx |
| ; CHECK-NEXT: .cfi_def_cfa_offset 16 |
| ; CHECK-NEXT: .cfi_offset %rbx, -16 |
| ; CHECK-NEXT: movq %rdi, %rbx |
| ; CHECK-NEXT: callq func@PLT |
| ; CHECK-NEXT: .Ltmp12: |
| ; CHECK-NEXT: movq %rbx, %rdi |
| ; CHECK-NEXT: callq consume@PLT |
| ; CHECK-NEXT: popq %rbx |
| ; CHECK-NEXT: .cfi_def_cfa_offset 8 |
| ; CHECK-NEXT: retq |
| entry: |
| %token1 = tail call token (i64, i32, void ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf(i64 0, i32 0, void ()* @func, i32 0, i32 0, i32 0, i32 0) ["deopt" (i32 0, i32 1, i32 7, i32 addrspace(1)* null, i32 9), "gc-live" (i32 addrspace(1)* null, i32 addrspace(1)* %a)] |
| %rel = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %token1, i32 0, i32 1) |
| call void @consume(i32 addrspace(1)* %rel) |
| ret void |
| } |
| |
| ; test multiple statepoints/relocates within single block. |
| ; relocates must be properly scheduled w.r.t. statepoints |
| define void @test_sched(float %0, i32 %1, i8 addrspace(1)* %2) gc "statepoint-example" { |
| ; CHECK-LABEL: test_sched: |
| ; CHECK: # %bb.0: # %entry |
| ; CHECK-NEXT: pushq %rbp |
| ; CHECK-NEXT: .cfi_def_cfa_offset 16 |
| ; CHECK-NEXT: pushq %rbx |
| ; CHECK-NEXT: .cfi_def_cfa_offset 24 |
| ; CHECK-NEXT: subq $24, %rsp |
| ; CHECK-NEXT: .cfi_def_cfa_offset 48 |
| ; CHECK-NEXT: .cfi_offset %rbx, -24 |
| ; CHECK-NEXT: .cfi_offset %rbp, -16 |
| ; CHECK-NEXT: movq %rsi, %rbx |
| ; CHECK-NEXT: movl %edi, %ebp |
| ; CHECK-NEXT: movss %xmm0, {{[-0-9]+}}(%r{{[sb]}}p) # 4-byte Spill |
| ; CHECK-NEXT: callq consume3@PLT |
| ; CHECK-NEXT: .Ltmp13: |
| ; CHECK-NEXT: xorps %xmm0, %xmm0 |
| ; CHECK-NEXT: cvtsi2sd %ebp, %xmm0 |
| ; CHECK-NEXT: movsd %xmm0, {{[-0-9]+}}(%r{{[sb]}}p) # 8-byte Spill |
| ; CHECK-NEXT: nopl 8(%rax,%rax) |
| ; CHECK-NEXT: .Ltmp14: |
| ; CHECK-NEXT: movsd {{[-0-9]+}}(%r{{[sb]}}p), %xmm0 # 8-byte Reload |
| ; CHECK-NEXT: # xmm0 = mem[0],zero |
| ; CHECK-NEXT: movsd %xmm0, {{[0-9]+}}(%rsp) |
| ; CHECK-NEXT: movss {{[-0-9]+}}(%r{{[sb]}}p), %xmm0 # 4-byte Reload |
| ; CHECK-NEXT: # xmm0 = mem[0],zero,zero,zero |
| ; CHECK-NEXT: movss %xmm0, (%rsp) |
| ; CHECK-NEXT: nopl 8(%rax,%rax) |
| ; CHECK-NEXT: .Ltmp15: |
| ; CHECK-NEXT: movsd {{[-0-9]+}}(%r{{[sb]}}p), %xmm0 # 8-byte Reload |
| ; CHECK-NEXT: # xmm0 = mem[0],zero |
| ; CHECK-NEXT: movsd %xmm0, {{[0-9]+}}(%rsp) |
| ; CHECK-NEXT: movss {{[-0-9]+}}(%r{{[sb]}}p), %xmm0 # 4-byte Reload |
| ; CHECK-NEXT: # xmm0 = mem[0],zero,zero,zero |
| ; CHECK-NEXT: movss %xmm0, (%rsp) |
| ; CHECK-NEXT: nopl 8(%rax,%rax) |
| ; CHECK-NEXT: .Ltmp16: |
| ; CHECK-NEXT: xorl %eax, %eax |
| ; CHECK-NEXT: xorpd %xmm0, %xmm0 |
| ; CHECK-NEXT: movsd {{[-0-9]+}}(%r{{[sb]}}p), %xmm1 # 8-byte Reload |
| ; CHECK-NEXT: # xmm1 = mem[0],zero |
| ; CHECK-NEXT: ucomisd %xmm0, %xmm1 |
| ; CHECK-NEXT: movabsq $9223372036854775807, %rdi # imm = 0x7FFFFFFFFFFFFFFF |
| ; CHECK-NEXT: cmovbeq %rax, %rdi |
| ; CHECK-NEXT: movsd %xmm1, {{[0-9]+}}(%rsp) |
| ; CHECK-NEXT: movss {{[-0-9]+}}(%r{{[sb]}}p), %xmm0 # 4-byte Reload |
| ; CHECK-NEXT: # xmm0 = mem[0],zero,zero,zero |
| ; CHECK-NEXT: movss %xmm0, (%rsp) |
| ; CHECK-NEXT: nopl 8(%rax,%rax) |
| ; CHECK-NEXT: .Ltmp17: |
| ; CHECK-NEXT: addq $24, %rsp |
| ; CHECK-NEXT: .cfi_def_cfa_offset 24 |
| ; CHECK-NEXT: popq %rbx |
| ; CHECK-NEXT: .cfi_def_cfa_offset 16 |
| ; CHECK-NEXT: popq %rbp |
| ; CHECK-NEXT: .cfi_def_cfa_offset 8 |
| ; CHECK-NEXT: retq |
| entry: |
| %token0 = call token (i64, i32, void (float)*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf32f(i64 2, i32 0, void (float)* nonnull @consume3, i32 1, i32 0, float %0, i32 0, i32 0) [ "gc-live"(i8 addrspace(1)* %2) ] |
| %reloc1 = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token %token0, i32 0, i32 0) ; (%2, %2) |
| %tmp1 = sitofp i32 %1 to double |
| %to_max.i29 = fcmp ogt double %tmp1, 0.000000e+00 |
| %token1 = call token (i64, i32, i32 (i32)*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i32i32f(i64 2, i32 5, i32 (i32)* nonnull @consume1, i32 1, i32 0, i32 undef, i32 0, i32 0) [ "gc-live"(i8 addrspace(1)* %reloc1) ] |
| %reloc2 = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token %token1, i32 0, i32 0) ; (%reloc1, %reloc1) |
| %reloc3 = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token %token1, i32 0, i32 0) ; (%reloc1, %reloc1) |
| %token2 = call token (i64, i32, i32 (i32)*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i32i32f(i64 2, i32 5, i32 (i32)* nonnull @consume1, i32 1, i32 0, i32 undef, i32 0, i32 0) [ "deopt"(float %0, double %tmp1), "gc-live"(i8 addrspace(1)* %reloc2, i8 addrspace(1)* %reloc3) ] |
| %reloc4 = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token %token2, i32 0, i32 0) ; (%reloc3, %reloc2) |
| %reloc5 = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token %token2, i32 1, i32 1) ; (%reloc3, %reloc3) |
| %token3 = call token (i64, i32, void (float)*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidf32f(i64 2, i32 5, void (float)* nonnull @consume3, i32 1, i32 0, float %0, i32 0, i32 0) [ "deopt"(float %0, double %tmp1), "gc-live"(i8 addrspace(1)* %reloc4, i8 addrspace(1)* %reloc5) ] |
| %reloc6 = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token %token3, i32 1, i32 0) ; (%reloc5, %reloc4) |
| %tmp5 = select i1 %to_max.i29, i64 9223372036854775807, i64 0 |
| %token4 = call token (i64, i32, float (i64)*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_f32i64f(i64 2, i32 5, float (i64)* nonnull @consume4, i32 1, i32 0, i64 %tmp5, i32 0, i32 0) [ "deopt"(float %0, double %tmp1), "gc-live"() ] |
| ret void |
| } |
| |
| declare token @llvm.experimental.gc.statepoint.p0f_f32i64f(i64 immarg, i32 immarg, float (i64)*, i32 immarg, i32 immarg, ...) |
| declare token @llvm.experimental.gc.statepoint.p0f_i32i32f(i64 immarg, i32 immarg, i32 (i32)*, i32 immarg, i32 immarg, ...) |
| declare token @llvm.experimental.gc.statepoint.p0f_isVoidf32f(i64 immarg, i32 immarg, void (float)*, i32 immarg, i32 immarg, ...) |
| declare token @llvm.experimental.gc.statepoint.p0f_i1f(i64, i32, i1 ()*, i32, i32, ...) |
| declare token @llvm.experimental.gc.statepoint.p0f_isVoidf(i64, i32, void ()*, i32, i32, ...) |
| declare i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token, i32, i32) |
| declare i64 addrspace(1)* @llvm.experimental.gc.relocate.p1i64(token, i32, i32) |
| declare i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token, i32, i32) |
| declare <2 x i8 addrspace(1)*> @llvm.experimental.gc.relocate.v2p1i8(token, i32, i32) |
| declare i1 @llvm.experimental.gc.result.i1(token) |