xref: /llvm-project/llvm/test/CodeGen/X86/statepoint-vreg-details.ll (revision cbdccb30c23f71f20d05b19256232419e7c5e517)
1; This file contains some of the same basic tests as statepoint-vreg.ll, but
2; focuses on examining the intermediate representation.  It's separate so that
3; the main file is easy to update with update_llc_test_checks.py
4
5; This run is to demonstrate what MIR SSA looks like.
6; RUN: llc -max-registers-for-gc-values=4 -stop-after finalize-isel < %s | FileCheck --check-prefix=CHECK-VREG %s
7; This run is to demonstrate register allocator work.
8; RUN: llc -max-registers-for-gc-values=4 -stop-after virtregrewriter < %s | FileCheck --check-prefix=CHECK-PREG %s
9
10target datalayout = "e-i64:64-f80:128-n8:16:32:64-S128"
11target triple = "x86_64-pc-linux-gnu"
12
13declare dso_local i1 @return_i1()
14declare dso_local void @func()
15declare dso_local void @consume(ptr addrspace(1))
16declare dso_local void @consume2(ptr addrspace(1), ptr addrspace(1))
17declare dso_local void @consume5(ptr addrspace(1), ptr addrspace(1), ptr addrspace(1), ptr addrspace(1), ptr addrspace(1))
18declare dso_local void @use1(ptr addrspace(1), ptr addrspace(1))
19declare dso_local void @bar(ptr addrspace(1), ptr addrspace(1))
20declare ptr addrspace(1) @dummy(i32)
21
22; test most simple relocate
23define i1 @test_relocate(ptr addrspace(1) %a) gc "statepoint-example" {
24; CHECK-VREG-LABEL: name:            test_relocate
25; CHECK-VREG:    %0:gr64 = COPY $rdi
26; CHECK-VREG:    %1:gr64 = STATEPOINT 0, 0, 0, @return_i1, 2, 0, 2, 0, 2, 0, 2, 1, %0(tied-def 0), 2, 0, 2, 1, 0, 0, csr_64, implicit-def $rsp, implicit-def $ssp, implicit-def $al
27; CHECK-VREG:    %2:gr8 = COPY $al
28; CHECK-VREG:    $rdi = COPY %1
29; CHECK-VREG:    CALL64pcrel32 @consume, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp
30
31; CHECK-PREG-LABEL: name:            test_relocate
32; CHECK-PREG:    renamable $rbx = COPY $rdi
33; CHECK-PREG:    renamable $rbx = STATEPOINT 0, 0, 0, @return_i1, 2, 0, 2, 0, 2, 0, 2, 1, killed renamable $rbx(tied-def 0), 2, 0, 2, 1, 0, 0, csr_64, implicit-def $rsp, implicit-def $ssp, implicit-def $al
34; CHECK-PREG:    renamable $bpl = COPY $al
35; CHECK-PREG:    $rdi = COPY killed renamable $rbx
36; CHECK-PREG:    CALL64pcrel32 @consume, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp
37
38entry:
39  %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)]
40  %rel1 = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token,  i32 0, i32 0)
41  %res1 = call zeroext i1 @llvm.experimental.gc.result.i1(token %safepoint_token)
42  call void @consume(ptr addrspace(1) %rel1)
43  ret i1 %res1
44}
45; test pointer variables intermixed with pointer constants
46define void @test_mixed(ptr addrspace(1) %a, ptr addrspace(1) %b, ptr addrspace(1) %c) gc "statepoint-example" {
47; CHECK-VREG-LABEL: name:            test_mixed
48; CHECK-VREG:    %2:gr64 = COPY $rdx
49; CHECK-VREG:    %1:gr64 = COPY $rsi
50; CHECK-VREG:    %0:gr64 = COPY $rdi
51; CHECK-VREG:    %3:gr64, %4:gr64, %5:gr64 = STATEPOINT 0, 0, 0, @func, 2, 0, 2, 0, 2, 0, 2, 4, %2(tied-def 0), 2, 0, %1(tied-def 1), %0(tied-def 2), 2, 0, 2, 4, 0, 0, 1, 1, 2, 2, 3, 3, csr_64, implicit-def $rsp, implicit-def $ssp
52; CHECK-VREG:    %6:gr32 = MOV32r0 implicit-def dead $eflags
53; CHECK-VREG:    %7:gr64 = SUBREG_TO_REG 0, killed %6, %subreg.sub_32bit
54; CHECK-VREG:    $rdi = COPY %5
55; CHECK-VREG:    $rsi = COPY %7
56; CHECK-VREG:    $rdx = COPY %4
57; CHECK-VREG:    $rcx = COPY %7
58; CHECK-VREG:    $r8 = COPY %3
59; CHECK-VREG:    CALL64pcrel32 @consume5, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit $rsi, implicit $rdx, implicit $rcx, implicit $r8, implicit-def $rsp, implicit-def $ssp
60
61; CHECK-PREG-LABEL: name:            test_mixed
62; CHECK-PREG:    renamable $rbx = COPY $rdx
63; CHECK-PREG:    renamable $r14 = COPY $rsi
64; CHECK-PREG:    renamable $r15 = COPY $rdi
65; CHECK-PREG:    renamable $rbx, renamable $r14, renamable $r15 = STATEPOINT 0, 0, 0, @func, 2, 0, 2, 0, 2, 0, 2, 4, killed renamable $rbx(tied-def 0), 2, 0, killed renamable $r14(tied-def 1), killed renamable $r15(tied-def 2), 2, 0, 2, 4, 0, 0, 1, 1, 2, 2, 3, 3, csr_64, implicit-def $rsp, implicit-def $ssp
66; CHECK-PREG:    $rdi = COPY killed renamable $r15
67; CHECK-PREG:    dead $esi = MOV32r0 implicit-def dead $eflags, implicit-def $rsi
68; CHECK-PREG:    $rdx = COPY killed renamable $r14
69; CHECK-PREG:    dead $ecx = MOV32r0 implicit-def dead $eflags, implicit-def $rcx
70; CHECK-PREG:    $r8 = COPY killed renamable $rbx
71; CHECK-PREG:    CALL64pcrel32 @consume5, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit $rsi, implicit $rdx, implicit killed $rcx, implicit killed $r8, implicit-def $rsp, implicit-def $ssp
72
73entry:
74  %safepoint_token = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(void ()) @func, i32 0, i32 0, i32 0, i32 0) ["gc-live" (ptr addrspace(1) %a, ptr addrspace(1) null, ptr addrspace(1) %b, ptr addrspace(1) null, ptr addrspace(1) %c)]
75  %rel1 = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token,  i32 0, i32 0)
76  %rel2 = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token,  i32 1, i32 1)
77  %rel3 = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token,  i32 2, i32 2)
78  %rel4 = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token,  i32 3, i32 3)
79  %rel5 = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token,  i32 4, i32 4)
80  call void @consume5(ptr addrspace(1) %rel1, ptr addrspace(1) %rel2, ptr addrspace(1) %rel3, ptr addrspace(1) %rel4, ptr addrspace(1) %rel5)
81  ret void
82}
83
84; same as above, but for alloca
85define ptr addrspace(1) @test_alloca(ptr addrspace(1) %ptr) gc "statepoint-example" {
86; CHECK-VREG-LABEL: name:            test_alloca
87; CHECK-VREG:    %0:gr64 = COPY $rdi
88; CHECK-VREG:    MOV64mr %stack.0.alloca, 1, $noreg, 0, $noreg, %0 :: (store (s64) into %ir.alloca)
89; CHECK-VREG:    %1:gr64 = STATEPOINT 0, 0, 0, @return_i1, 2, 0, 2, 0, 2, 0, 2, 1, %0(tied-def 0), 2, 1, 0, %stack.0.alloca, 0, 2, 1, 0, 0, csr_64, implicit-def $rsp, implicit-def $ssp, implicit-def $al :: (volatile load store (s64) on %stack.0.alloca)
90; CHECK-VREG:    %2:gr8 = COPY $al
91; CHECK-VREG:    %3:gr64 = MOV64rm %stack.0.alloca, 1, $noreg, 0, $noreg :: (dereferenceable load (s64) from %ir.alloca)
92; CHECK-VREG:    $rdi = COPY %1
93; CHECK-VREG:    CALL64pcrel32 @consume, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp
94
95; CHECK-PREG-LABEL: name:            test_alloca
96; CHECK-PREG:    renamable $rbx = COPY $rdi
97; CHECK-PREG:    MOV64mr %stack.0.alloca, 1, $noreg, 0, $noreg, renamable $rbx :: (store (s64) into %ir.alloca)
98; CHECK-PREG:    renamable $rbx = STATEPOINT 0, 0, 0, @return_i1, 2, 0, 2, 0, 2, 0, 2, 1, killed renamable $rbx(tied-def 0), 2, 1, 0, %stack.0.alloca, 0, 2, 1, 0, 0, csr_64, implicit-def $rsp, implicit-def $ssp, implicit-def dead $al :: (volatile load store (s64) on %stack.0.alloca)
99; CHECK-PREG:    renamable $r14 = MOV64rm %stack.0.alloca, 1, $noreg, 0, $noreg :: (dereferenceable load (s64) from %ir.alloca)
100; CHECK-PREG:    $rdi = COPY killed renamable $rbx
101; CHECK-PREG:    CALL64pcrel32 @consume, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp
102
103entry:
104  %alloca = alloca ptr addrspace(1), align 8
105  store ptr addrspace(1) %ptr, ptr %alloca
106  %safepoint_token = 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 %alloca, ptr addrspace(1) %ptr)]
107  %rel1 = load ptr addrspace(1), ptr %alloca
108  %rel2 = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token,  i32 1, i32 1)
109  call void @consume(ptr addrspace(1) %rel2)
110  ret ptr addrspace(1) %rel1
111}
112
113; test base != derived
114define void @test_base_derived(ptr addrspace(1) %base, ptr addrspace(1) %derived) gc "statepoint-example" {
115; CHECK-VREG-LABEL: name:            test_base_derived
116; CHECK-VREG:    %1:gr64 = COPY $rsi
117; CHECK-VREG:    %0:gr64 = COPY $rdi
118; CHECK-VREG:    %2:gr64, %3:gr64 = STATEPOINT 0, 0, 0, @func, 2, 0, 2, 0, 2, 0, 2, 2, %1(tied-def 0), %0(tied-def 1), 2, 0, 2, 1, 1, 0, csr_64, implicit-def $rsp, implicit-def $ssp
119; CHECK-VREG:    $rdi = COPY %2
120; CHECK-VREG:    CALL64pcrel32 @consume, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp
121
122; CHECK-PREG-LABEL: name:            test_base_derived
123; CHECK-PREG:    renamable $rbx = COPY $rsi
124; CHECK-PREG:    renamable $rbx, dead renamable $r14 = STATEPOINT 0, 0, 0, @func, 2, 0, 2, 0, 2, 0, 2, 2, killed renamable $rbx(tied-def 0), killed renamable $r14(tied-def 1), 2, 0, 2, 1, 1, 0, csr_64, implicit-def $rsp, implicit-def $ssp
125; CHECK-PREG:    $rdi = COPY killed renamable $rbx
126; CHECK-PREG:    CALL64pcrel32 @consume, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp
127
128  %safepoint_token = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(void ()) @func, i32 0, i32 0, i32 0, i32 0) ["gc-live" (ptr addrspace(1) %base, ptr addrspace(1) %derived)]
129  %reloc = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token,  i32 0, i32 1)
130  call void @consume(ptr addrspace(1) %reloc)
131  ret void
132}
133
134; deopt GC pointer not present in GC args must be spilled
135define void @test_deopt_gcpointer(ptr addrspace(1) %a, ptr addrspace(1) %b) gc "statepoint-example" {
136; CHECK-VREG-LABEL: name:            test_deopt_gcpointer
137; CHECK-VREG:    %1:gr64 = COPY $rsi
138; CHECK-VREG:    %0:gr64 = COPY $rdi
139; CHECK-VREG:    %2:gr64, %3:gr64 = STATEPOINT 0, 0, 0, @func, 2, 0, 2, 0, 2, 1, %0, 2, 2, %1(tied-def 0), %0(tied-def 1), 2, 0, 2, 2, 0, 0, 1, 1, csr_64, implicit-def $rsp, implicit-def $ssp
140; CHECK-VREG:    $rdi = COPY %2
141; CHECK-VREG:    CALL64pcrel32 @consume, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp
142; CHECK-VREG:    RET 0
143
144; CHECK-PREG-LABEL: name:            test_deopt_gcpointer
145; CHECK-PREG:    renamable $rbx = COPY $rsi
146; CHECK-PREG:    renamable $r14 = COPY $rdi
147; CHECK-PREG:    renamable $rbx, dead renamable $r14 = STATEPOINT 0, 0, 0, @func, 2, 0, 2, 0, 2, 1, killed renamable $r14, 2, 2, killed renamable $rbx(tied-def 0), renamable $r14(tied-def 1), 2, 0, 2, 2, 0, 0, 1, 1, csr_64, implicit-def $rsp, implicit-def $ssp
148; CHECK-PREG:    $rdi = COPY killed renamable $rbx
149; CHECK-PREG:    CALL64pcrel32 @consume, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp
150
151  %safepoint_token = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(void ()) @func, i32 0, i32 0, i32 0, i32 0) ["deopt" (ptr addrspace(1) %a), "gc-live" (ptr addrspace(1) %b)]
152  %rel = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token,  i32 0, i32 0)
153  call void @consume(ptr addrspace(1) %rel)
154  ret void
155}
156
157;; Two gc.relocates of the same input, should require only a single spill/fill
158define void @test_gcrelocate_uniqueing(ptr addrspace(1) %ptr) gc "statepoint-example" {
159; CHECK-VREG-LABEL: name:            test_gcrelocate_uniqueing
160; CHECK-VREG:    %0:gr64 = COPY $rdi
161; CHECK-VREG:    %1:gr64 = STATEPOINT 0, 0, 0, @func, 2, 0, 2, 0, 2, 2, %0, 2, 4278124286, 2, 1, %0(tied-def 0), 2, 0, 2, 1, 0, 0, csr_64, implicit-def $rsp, implicit-def $ssp
162; CHECK-VREG:    $rdi = COPY %1
163; CHECK-VREG:    $rsi = COPY %1
164; CHECK-VREG:    CALL64pcrel32 @consume2, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit $rsi, implicit-def $rsp, implicit-def $ssp
165
166; CHECK-PREG-LABEL: name:            test_gcrelocate_uniqueing
167; CHECK-PREG:    renamable $rbx = COPY $rdi
168; CHECK-PREG:    renamable $rbx = STATEPOINT 0, 0, 0, @func, 2, 0, 2, 0, 2, 2, killed renamable $rbx, 2, 4278124286, 2, 1, renamable $rbx(tied-def 0), 2, 0, 2, 1, 0, 0, csr_64, implicit-def $rsp, implicit-def $ssp
169; CHECK-PREG:    $rdi = COPY renamable $rbx
170; CHECK-PREG:    $rsi = COPY killed renamable $rbx
171; CHECK-PREG:    CALL64pcrel32 @consume2, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit killed $rsi, implicit-def $rsp, implicit-def $ssp
172
173  %tok = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(void ()) @func, i32 0, i32 0, i32 0, i32 0) ["deopt" (ptr addrspace(1) %ptr, i32 undef), "gc-live" (ptr addrspace(1) %ptr, ptr addrspace(1) %ptr)]
174  %a = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %tok, i32 0, i32 0)
175  %b = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %tok, i32 1, i32 1)
176  call void @consume2(ptr addrspace(1) %a, ptr addrspace(1) %b)
177  ret void
178}
179
180; Two gc.relocates of a bitcasted pointer should only require a single spill/fill
181define void @test_gcptr_uniqueing(ptr addrspace(1) %ptr) gc "statepoint-example" {
182; CHECK-VREG-LABEL: name:            test_gcptr_uniqueing
183; CHECK-VREG:    %0:gr64 = COPY $rdi
184; CHECK-VREG:    ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
185; CHECK-VREG:    %1:gr64 = STATEPOINT 0, 0, 0, @func, 2, 0, 2, 0, 2, 2, %0, 2, 4278124286, 2, 1, %0(tied-def 0), 2, 0, 2, 1, 0, 0, csr_64, implicit-def $rsp, implicit-def $ssp
186; CHECK-VREG:    ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
187; CHECK-VREG:    ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
188; CHECK-VREG:    $rdi = COPY %1
189; CHECK-VREG:    $rsi = COPY %1
190; CHECK-VREG:    CALL64pcrel32 @use1, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit $rsi, implicit-def $rsp, implicit-def $ssp
191
192; CHECK-PREG-LABEL: name:            test_gcptr_uniqueing
193; CHECK-PREG:    renamable $rbx = COPY $rdi
194; CHECK-PREG:    renamable $rbx = STATEPOINT 0, 0, 0, @func, 2, 0, 2, 0, 2, 2, killed renamable $rbx, 2, 4278124286, 2, 1, renamable $rbx(tied-def 0), 2, 0, 2, 1, 0, 0, csr_64, implicit-def $rsp, implicit-def $ssp
195; CHECK-PREG:    $rdi = COPY renamable $rbx
196; CHECK-PREG:    $rsi = COPY killed renamable $rbx
197; CHECK-PREG:    CALL64pcrel32 @use1, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit killed $rsi, implicit-def $rsp, implicit-def $ssp
198
199  %tok = tail call token (i64, i32, ptr, i32, i32, ...)
200      @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(void ()) @func, i32 0, i32 0, i32 0, i32 0) ["deopt" (ptr addrspace(1) %ptr, i32 undef), "gc-live" (ptr addrspace(1) %ptr, ptr addrspace(1) %ptr)]
201  %a = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %tok, i32 0, i32 0)
202  %b = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %tok, i32 1, i32 1)
203  call void @use1(ptr addrspace(1) %a, ptr addrspace(1) %b)
204  ret void
205}
206
207define i1 @test_cross_bb(ptr addrspace(1) %a, i1 %external_cond) gc "statepoint-example" {
208; CHECK-VREG-LABEL: name:            test_cross_bb
209; CHECK-VREG:  bb.0.entry:
210; CHECK-VREG:         %1:gr32 = COPY $esi
211; CHECK-VREG-NEXT:    %0:gr64 = COPY $rdi
212; CHECK-VREG-NEXT:    %4:gr8 = COPY %1.sub_8bit
213; CHECK-VREG-NEXT:    ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
214; CHECK-VREG-NEXT:    %2:gr64 = STATEPOINT 0, 0, 0, @return_i1, 2, 0, 2, 0, 2, 0, 2, 1, %0(tied-def 0), 2, 0, 2, 1, 0, 0, csr_64, implicit-def $rsp, implicit-def $ssp, implicit-def $al
215; CHECK-VREG-NEXT:    ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
216; CHECK-VREG-NEXT:    %5:gr8 = COPY $al
217; CHECK-VREG-NEXT:    %3:gr8 = COPY %5
218; CHECK-VREG-NEXT:    TEST8ri killed %4, 1, implicit-def $eflags
219; CHECK-VREG-NEXT:    JCC_1 %bb.2, 4, implicit $eflags
220; CHECK-VREG-NEXT:    JMP_1 %bb.1
221; CHECK-VREG:       bb.1.left:
222; CHECK-VREG-NEXT:    ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
223; CHECK-VREG-NEXT:    $rdi = COPY %2
224; CHECK-VREG-NEXT:    CALL64pcrel32 @consume, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp
225; CHECK-VREG-NEXT:    ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
226; CHECK-VREG-NEXT:    $al = COPY %3
227; CHECK-VREG-NEXT:    RET 0, $al
228; CHECK-VREG:       bb.2.right:
229; CHECK-VREG-NEXT:    %6:gr8 = MOV8ri 1
230; CHECK-VREG-NEXT:    $al = COPY %6
231; CHECK-VREG-NEXT:    RET 0, $al
232
233entry:
234  %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)]
235  br i1 %external_cond, label %left, label %right
236
237left:
238  %call1 = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token,  i32 0, i32 0)
239  %call2 = call zeroext i1 @llvm.experimental.gc.result.i1(token %safepoint_token)
240  call void @consume(ptr addrspace(1) %call1)
241  ret i1 %call2
242
243right:
244  ret i1 true
245}
246
247; Local and non-local relocates of the same value
248; CHECK-VREG-LABEL: name:            test_local_non_local_reloc
249; CHECK-VREG:  bb.0.entry:
250; CHECK-VREG:    %2:gr64 = COPY $rsi
251; CHECK-VREG:    %1:gr32 = COPY $edi
252; CHECK-VREG:    %4:gr8 = COPY %1.sub_8bit
253; CHECK-VREG:    ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
254; CHECK-VREG:    %5:gr32 = MOV32r0 implicit-def dead $eflags
255; CHECK-VREG:    $edi = COPY %5
256; CHECK-VREG:    %6:gr64 = IMPLICIT_DEF
257; CHECK-VREG:    %0:gr64 = STATEPOINT 2, 5, 1, killed %6, $edi, 2, 0, 2, 0, 2, 0, 2, 1, %2(tied-def 0), 2, 0, 2, 1, 0, 0, csr_64, implicit-def $rsp, implicit-def $ssp, implicit-def $rax
258; CHECK-VREG:    ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
259; CHECK-VREG:    %7:gr64 = COPY $rax
260; CHECK-VREG:    %3:gr64 = COPY %0
261; CHECK-VREG:    TEST8ri killed %4, 1, implicit-def $eflags
262; CHECK-VREG:    JCC_1 %bb.2, 5, implicit $eflags
263; CHECK-VREG:    JMP_1 %bb.1
264; CHECK-VREG:  bb.1.left:
265; CHECK-VREG:    $rax = COPY %3
266; CHECK-VREG:    RET 0, $rax
267; CHECK-VREG:  bb.2.right:
268; CHECK-VREG:    $rax = COPY %0
269; CHECK-VREG:    RET 0, $rax
270define ptr addrspace(1) @test_local_non_local_reloc(i1 %c, ptr addrspace(1) %p) gc "statepoint-example" {
271entry:
272  %statepoint = call token (i64, i32, ptr addrspace(1) (i32)*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 2, i32 5, ptr addrspace(1) (i32)* nonnull elementtype(ptr addrspace(1) (i32)) @dummy, i32 1, i32 0, i32 0, i32 0, i32 0) [ "deopt"(), "gc-live"(ptr addrspace(1) %p) ]
273  %p.relocated = call coldcc ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %statepoint, i32 0, i32 0) ; (%p, %p)
274  br i1 %c, label %right, label %left
275
276left:
277  %p.relocated.2 = call coldcc ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %statepoint, i32 0, i32 0) ; (%p, %p)
278  ret ptr addrspace(1) %p.relocated.2
279
280right:
281  ret ptr addrspace(1) %p.relocated
282}
283
284; No need to check post-regalloc output as it is the same
285define i1 @duplicate_reloc() gc "statepoint-example" {
286; CHECK-VREG-LABEL: name:            duplicate_reloc
287; CHECK-VREG:  bb.0.entry:
288; CHECK-VREG:    STATEPOINT 0, 0, 0, @func, 2, 0, 2, 0, 2, 0, 2, 1, 2, 0, 2, 0, 2, 1, 0, 0, csr_64, implicit-def $rsp, implicit-def $ssp
289; CHECK-VREG:    STATEPOINT 0, 0, 0, @func, 2, 0, 2, 0, 2, 0, 2, 1, 2, 0, 2, 0, 2, 1, 0, 0, csr_64, implicit-def $rsp, implicit-def $ssp
290; CHECK-VREG:    %0:gr8 = MOV8ri 1
291; CHECK-VREG:    $al = COPY %0
292; CHECK-VREG:    RET 0, $al
293
294entry:
295  %safepoint_token = call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(void ()) @func, i32 0, i32 0, i32 0, i32 0) ["gc-live" (ptr addrspace(1) null, ptr addrspace(1) null)]
296  %base = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token,  i32 0, i32 0)
297  %derived = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token,  i32 0, i32 1)
298  %safepoint_token2 = call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(void ()) @func, i32 0, i32 0, i32 0, i32 0) ["gc-live" (ptr addrspace(1) %base, ptr addrspace(1) %derived)]
299  %base_reloc = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token2,  i32 0, i32 0)
300  %derived_reloc = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token2,  i32 0, i32 1)
301  %cmp1 = icmp eq ptr addrspace(1) %base_reloc, null
302  %cmp2 = icmp eq ptr addrspace(1) %derived_reloc, null
303  %cmp = and i1 %cmp1, %cmp2
304  ret i1 %cmp
305}
306
307; Vectors cannot go in VRegs
308; No need to check post-regalloc output as it is lowered using old scheme
309define <2 x ptr addrspace(1)> @test_vector(<2 x ptr addrspace(1)> %obj) gc "statepoint-example" {
310; CHECK-VREG-LABEL: name:            test_vector
311; CHECK-VREG:    %0:vr128 = COPY $xmm0
312; CHECK-VREG:    MOVAPSmr %stack.0, 1, $noreg, 0, $noreg, %0 :: (store (s128) into %stack.0)
313; CHECK-VREG:    STATEPOINT 0, 0, 0, @func, 2, 0, 2, 0, 2, 0, 2, 1, 1, 16, %stack.0, 0, 2, 0, 2, 1, 0, 0, csr_64, implicit-def $rsp, implicit-def $ssp :: (volatile load store (s128) on %stack.0)
314; CHECK-VREG:    %1:vr128 = MOVAPSrm %stack.0, 1, $noreg, 0, $noreg :: (load (s128) from %stack.0)
315; CHECK-VREG:    $xmm0 = COPY %1
316; CHECK-VREG:    RET 0, $xmm0
317
318entry:
319  %safepoint_token = call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(void ()) @func, i32 0, i32 0, i32 0, i32 0) ["gc-live" (<2 x ptr addrspace(1)> %obj)]
320  %obj.relocated = call coldcc <2 x ptr addrspace(1)> @llvm.experimental.gc.relocate.v2p1(token %safepoint_token, i32 0, i32 0) ; (%obj, %obj)
321  ret <2 x ptr addrspace(1)> %obj.relocated
322}
323
324
325; test limit on amount of vregs
326define void @test_limit(ptr addrspace(1) %a, ptr addrspace(1) %b, ptr addrspace(1) %c, ptr addrspace(1) %d, ptr addrspace(1)  %e) gc "statepoint-example" {
327; CHECK-VREG-LABEL: name:            test_limit
328; CHECK-VREG:    %4:gr64 = COPY $r8
329; CHECK-VREG:    %3:gr64 = COPY $rcx
330; CHECK-VREG:    %2:gr64 = COPY $rdx
331; CHECK-VREG:    %1:gr64 = COPY $rsi
332; CHECK-VREG:    %0:gr64 = COPY $rdi
333; CHECK-VREG:    MOV64mr %stack.0, 1, $noreg, 0, $noreg, %0 :: (store (s64) into %stack.0)
334; CHECK-VREG:    %5:gr64, %6:gr64, %7:gr64, %8:gr64 = STATEPOINT 0, 0, 0, @func, 2, 0, 2, 0, 2, 0, 2, 5, %4(tied-def 0), %3(tied-def 1), %2(tied-def 2), %1(tied-def 3), 1, 8, %stack.0, 0, 2, 0, 2, 5, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, csr_64, implicit-def $rsp, implicit-def $ssp :: (volatile load store (s64) on %stack.0)
335; CHECK-VREG:    %9:gr64 = MOV64rm %stack.0, 1, $noreg, 0, $noreg :: (load (s64) from %stack.0)
336; CHECK-VREG:    $rdi = COPY %9
337; CHECK-VREG:    $rsi = COPY %8
338; CHECK-VREG:    $rdx = COPY %7
339; CHECK-VREG:    $rcx = COPY %6
340; CHECK-VREG:    $r8 = COPY %5
341; CHECK-VREG:    CALL64pcrel32 @consume5, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit $rsi, implicit $rdx, implicit $rcx, implicit $r8, implicit-def $rsp, implicit-def $ssp
342; CHECK-VREG:    RET 0
343entry:
344  %safepoint_token = tail call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 0, i32 0, ptr elementtype(void ()) @func, i32 0, i32 0, i32 0, i32 0) ["gc-live" (ptr addrspace(1) %a, ptr addrspace(1) %b, ptr addrspace(1) %c, ptr addrspace(1) %d, ptr addrspace(1) %e)]
345  %rel1 = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token,  i32 0, i32 0)
346  %rel2 = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token,  i32 1, i32 1)
347  %rel3 = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token,  i32 2, i32 2)
348  %rel4 = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token,  i32 3, i32 3)
349  %rel5 = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token,  i32 4, i32 4)
350  call void @consume5(ptr addrspace(1) %rel1, ptr addrspace(1) %rel2, ptr addrspace(1) %rel3, ptr addrspace(1) %rel4, ptr addrspace(1) %rel5)
351  ret void
352}
353
354; Test that CopyFromReg emitted during ISEL processing of gc.relocate are properly ordered w.r.t. statepoint.
355define ptr addrspace(1) @test_isel_sched(ptr addrspace(1) %0, ptr addrspace(1) %1, i32 %2) gc "statepoint-example" {
356;CHECK-VREG-LABEL: name:            test_isel_sched
357;CHECK-VREG:  bb.0.entry:
358;CHECK-VREG:        %2:gr32 = COPY $edx
359;CHECK-VREG:        %1:gr64 = COPY $rsi
360;CHECK-VREG:        %0:gr64 = COPY $rdi
361;CHECK-VREG:        TEST32rr %2, %2, implicit-def $eflags
362;CHECK-VREG:        %3:gr64 = CMOV64rr %1, %0, 4, implicit $eflags
363;CHECK-VREG:        %4:gr32 = MOV32r0 implicit-def dead $eflags
364;CHECK-VREG:        %5:gr64 = SUBREG_TO_REG 0, killed %4, %subreg.sub_32bit
365;CHECK-VREG:        $rdi = COPY %5
366;CHECK-VREG:        $rsi = COPY %3
367;CHECK-VREG:        %6:gr64, %7:gr64 = STATEPOINT 10, 0, 2, @bar, $rdi, $rsi, 2, 0, 2, 0, 2, 0, 2, 2, %1(tied-def 0), %0(tied-def 1), 2, 0, 2, 2, 0, 0, 1, 1, csr_64, implicit-def $rsp, implicit-def $ssp
368;CHECK-VREG:        TEST32rr %2, %2, implicit-def $eflags
369;CHECK-VREG:        %8:gr64 = CMOV64rr %6, killed %7, 4, implicit $eflags
370;CHECK-VREG:        $rax = COPY %8
371;CHECK-VREG:        RET 0, $rax
372entry:
373  %cmp = icmp eq i32 %2, 0
374  %ptr = select i1 %cmp, ptr addrspace(1) %0, ptr addrspace(1) %1
375  %token = call token (i64, i32, ptr, i32, i32, ...) @llvm.experimental.gc.statepoint.p0(i64 10, i32 0, ptr elementtype(void (ptr addrspace(1), ptr addrspace(1))) @bar, i32 2, i32 0, ptr addrspace(1) null, ptr addrspace(1) %ptr, i32 0, i32 0) [ "deopt"(), "gc-live"(ptr addrspace(1) %0, ptr addrspace(1) %1) ]
376  %rel0 = call coldcc ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %token, i32 0, i32 0)
377  %rel1 = call coldcc ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %token, i32 1, i32 1)
378  %res = select i1 %cmp, ptr addrspace(1) %rel0, ptr addrspace(1) %rel1
379  ret ptr addrspace(1) %res
380}
381
382; Check that ISEL of gc.relocate used in other BB does not generate extra COPY instruction.
383define i1 @test_cross_bb_reloc(ptr addrspace(1) %a, i1 %external_cond) gc "statepoint-example" {
384; CHECK-VREG-LABEL: test_cross_bb_reloc
385; CHECK-VREG:    bb.0.entry:
386; CHECK-VREG:      [[VREG:%[^ ]+]]:gr64 = STATEPOINT 0, 0, 0, @return_i1, 2, 0, 2, 0, 2, 0, 2, 1, %2(tied-def 0), 2, 0, 2, 1, 0, 0, csr_64, implicit-def $rsp, implicit-def $ssp, implicit-def $al
387; CHECK-VREG-NOT:  COPY [[VREG]]
388; CHECK-VREG:    bb.1.left:
389; CHECK-VREG:      $rdi = COPY [[VREG]]
390; CHECK-VREG:      CALL64pcrel32 @consume, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp
391; CHECK-VREG:      $al = COPY %1
392; CHECK-VREG:      RET 0, $al
393
394entry:
395  %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)]
396  %call1 = call ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token %safepoint_token,  i32 0, i32 0)
397  %call2 = call zeroext i1 @llvm.experimental.gc.result.i1(token %safepoint_token)
398  br i1 %external_cond, label %left, label %right
399
400left:
401  call void @consume(ptr addrspace(1) %call1)
402  ret i1 %call2
403
404right:
405  ret i1 true
406}
407
408declare token @llvm.experimental.gc.statepoint.p0(i64, i32, ptr, i32, i32, ...)
409declare dso_local ptr addrspace(1) @llvm.experimental.gc.relocate.p1(token, i32, i32)
410declare <2 x ptr addrspace(1)> @llvm.experimental.gc.relocate.v2p1(token, i32, i32)
411declare dso_local i1 @llvm.experimental.gc.result.i1(token)
412
413