• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(i32 addrspace(1)*)
16declare dso_local void @consume2(i32 addrspace(1)*, i32 addrspace(1)*)
17declare dso_local void @consume5(i32 addrspace(1)*, i32 addrspace(1)*, i32 addrspace(1)*, i32 addrspace(1)*, i32 addrspace(1)*)
18declare dso_local void @use1(i32 addrspace(1)*, i8 addrspace(1)*)
19declare dso_local i32* @fake_personality_function()
20declare dso_local i32 @foo(i32, i8 addrspace(1)*, i32, i32, i32)
21declare dso_local void @bar(i8 addrspace(1)*, i8 addrspace(1)*)
22
23; test most simple relocate
24define i1 @test_relocate(i32 addrspace(1)* %a) gc "statepoint-example" {
25; CHECK-VREG-LABEL: name:            test_relocate
26; CHECK-VREG:    %0:gr64 = COPY $rdi
27; 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
28; CHECK-VREG:    %2:gr8 = COPY $al
29; CHECK-VREG:    $rdi = COPY %1
30; CHECK-VREG:    CALL64pcrel32 @consume, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp
31
32; CHECK-PREG-LABEL: name:            test_relocate
33; CHECK-PREG:    renamable $rbx = COPY $rdi
34; 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
35; CHECK-PREG:    renamable $bpl = COPY killed $al
36; CHECK-PREG:    $rdi = COPY killed renamable $rbx
37; CHECK-PREG:    CALL64pcrel32 @consume, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp
38
39entry:
40  %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)]
41  %rel1 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 0, i32 0)
42  %res1 = call zeroext i1 @llvm.experimental.gc.result.i1(token %safepoint_token)
43  call void @consume(i32 addrspace(1)* %rel1)
44  ret i1 %res1
45}
46; test pointer variables intermixed with pointer constants
47define void @test_mixed(i32 addrspace(1)* %a, i32 addrspace(1)* %b, i32 addrspace(1)* %c) gc "statepoint-example" {
48; CHECK-VREG-LABEL: name:            test_mixed
49; CHECK-VREG:    %2:gr64 = COPY $rdx
50; CHECK-VREG:    %1:gr64 = COPY $rsi
51; CHECK-VREG:    %0:gr64 = COPY $rdi
52; 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
53; CHECK-VREG:    %6:gr32 = MOV32r0 implicit-def dead $eflags
54; CHECK-VREG:    %7:gr64 = SUBREG_TO_REG 0, killed %6, %subreg.sub_32bit
55; CHECK-VREG:    $rdi = COPY %5
56; CHECK-VREG:    $rsi = COPY %7
57; CHECK-VREG:    $rdx = COPY %4
58; CHECK-VREG:    $rcx = COPY %7
59; CHECK-VREG:    $r8 = COPY %3
60; 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
61
62; CHECK-PREG-LABEL: name:            test_mixed
63; CHECK-PREG:    renamable $r14 = COPY $rdx
64; CHECK-PREG:    renamable $r15 = COPY $rsi
65; CHECK-PREG:    renamable $rbx = COPY $rdi
66; CHECK-PREG:    renamable $r14, renamable $r15, renamable $rbx = STATEPOINT 0, 0, 0, @func, 2, 0, 2, 0, 2, 0, 2, 4, killed renamable $r14(tied-def 0), 2, 0, killed renamable $r15(tied-def 1), killed renamable $rbx(tied-def 2), 2, 0, 2, 4, 0, 0, 1, 1, 2, 2, 3, 3, csr_64, implicit-def $rsp, implicit-def $ssp
67; CHECK-PREG:    $rdi = COPY killed renamable $rbx
68; CHECK-PREG:    dead $esi = MOV32r0 implicit-def dead $eflags, implicit-def $rsi
69; CHECK-PREG:    $rdx = COPY killed renamable $r15
70; CHECK-PREG:    dead $ecx = MOV32r0 implicit-def dead $eflags, implicit-def $rcx
71; CHECK-PREG:    $r8 = COPY killed renamable $r14
72; 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
73
74entry:
75  %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)]
76  %rel1 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 0, i32 0)
77  %rel2 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 1, i32 1)
78  %rel3 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 2, i32 2)
79  %rel4 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 3, i32 3)
80  %rel5 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 4, i32 4)
81  call void @consume5(i32 addrspace(1)* %rel1, i32 addrspace(1)* %rel2, i32 addrspace(1)* %rel3, i32 addrspace(1)* %rel4, i32 addrspace(1)* %rel5)
82  ret void
83}
84
85; same as above, but for alloca
86define i32 addrspace(1)* @test_alloca(i32 addrspace(1)* %ptr) gc "statepoint-example" {
87; CHECK-VREG-LABEL: name:            test_alloca
88; CHECK-VREG:    %0:gr64 = COPY $rdi
89; CHECK-VREG:    MOV64mr %stack.0.alloca, 1, $noreg, 0, $noreg, %0 :: (store 8 into %ir.alloca)
90; 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 8 on %stack.0.alloca)
91; CHECK-VREG:    %2:gr8 = COPY $al
92; CHECK-VREG:    %3:gr64 = MOV64rm %stack.0.alloca, 1, $noreg, 0, $noreg :: (dereferenceable load 8 from %ir.alloca)
93; CHECK-VREG:    $rdi = COPY %1
94; CHECK-VREG:    CALL64pcrel32 @consume, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp
95
96; CHECK-PREG-LABEL: name:            test_alloca
97; CHECK-PREG:    renamable $rbx = COPY $rdi
98; CHECK-PREG:    MOV64mr %stack.0.alloca, 1, $noreg, 0, $noreg, renamable $rbx :: (store 8 into %ir.alloca)
99; 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 8 on %stack.0.alloca)
100; CHECK-PREG:    renamable $r14 = MOV64rm %stack.0.alloca, 1, $noreg, 0, $noreg :: (dereferenceable load 8 from %ir.alloca)
101; CHECK-PREG:    $rdi = COPY killed renamable $rbx
102; CHECK-PREG:    CALL64pcrel32 @consume, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp
103
104entry:
105  %alloca = alloca i32 addrspace(1)*, align 8
106  store i32 addrspace(1)* %ptr, i32 addrspace(1)** %alloca
107  %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)]
108  %rel1 = load i32 addrspace(1)*, i32 addrspace(1)** %alloca
109  %rel2 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 1, i32 1)
110  call void @consume(i32 addrspace(1)* %rel2)
111  ret i32 addrspace(1)* %rel1
112}
113
114; test base != derived
115define void @test_base_derived(i32 addrspace(1)* %base, i32 addrspace(1)* %derived) gc "statepoint-example" {
116; CHECK-VREG-LABEL: name:            test_base_derived
117; CHECK-VREG:    %1:gr64 = COPY $rsi
118; CHECK-VREG:    %0:gr64 = COPY $rdi
119; 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
120; CHECK-VREG:    $rdi = COPY %2
121; CHECK-VREG:    CALL64pcrel32 @consume, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp
122
123; CHECK-PREG-LABEL: name:            test_base_derived
124; CHECK-PREG:    renamable $rbx = COPY $rsi
125; 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
126; CHECK-PREG:    $rdi = COPY killed renamable $rbx
127; CHECK-PREG:    CALL64pcrel32 @consume, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp
128
129  %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)]
130  %reloc = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 0, i32 1)
131  call void @consume(i32 addrspace(1)* %reloc)
132  ret void
133}
134
135; deopt GC pointer not present in GC args must be spilled
136define void @test_deopt_gcpointer(i32 addrspace(1)* %a, i32 addrspace(1)* %b) gc "statepoint-example" {
137; CHECK-VREG-LABEL: name:            test_deopt_gcpointer
138; CHECK-VREG:    %1:gr64 = COPY $rsi
139; CHECK-VREG:    %0:gr64 = COPY $rdi
140; CHECK-VREG:    MOV64mr %stack.0, 1, $noreg, 0, $noreg, %0 :: (store 8 into %stack.0)
141; CHECK-VREG:    %2:gr64 = STATEPOINT 0, 0, 0, @func, 2, 0, 2, 0, 2, 1, 1, 8, %stack.0, 0, 2, 1, %1(tied-def 0), 2, 0, 2, 1, 0, 0, csr_64, implicit-def $rsp, implicit-def $ssp :: (volatile load store 8 on %stack.0)
142; CHECK-VREG:    $rdi = COPY %2
143; CHECK-VREG:    CALL64pcrel32 @consume, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp
144; CHECK-VREG:    RET 0
145
146; CHECK-PREG-LABEL: name:            test_deopt_gcpointer
147; CHECK-PREG:    renamable $rbx = COPY $rsi
148; CHECK-PREG:    MOV64mr %stack.0, 1, $noreg, 0, $noreg, killed renamable $rdi :: (store 8 into %stack.0)
149; CHECK-PREG:    renamable $rbx = STATEPOINT 0, 0, 0, @func, 2, 0, 2, 0, 2, 1, 1, 8, %stack.0, 0, 2, 1, killed renamable $rbx(tied-def 0), 2, 0, 2, 1, 0, 0, csr_64, implicit-def $rsp, implicit-def $ssp :: (volatile load store 8 on %stack.0)
150; CHECK-PREG:    $rdi = COPY killed renamable $rbx
151; CHECK-PREG:    CALL64pcrel32 @consume, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp
152
153  %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)]
154  %rel = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 0, i32 0)
155  call void @consume(i32 addrspace(1)* %rel)
156  ret void
157}
158
159;; Two gc.relocates of the same input, should require only a single spill/fill
160define void @test_gcrelocate_uniqueing(i32 addrspace(1)* %ptr) gc "statepoint-example" {
161; CHECK-VREG-LABEL: name:            test_gcrelocate_uniqueing
162; CHECK-VREG:    %0:gr64 = COPY $rdi
163; 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
164; CHECK-VREG:    $rdi = COPY %1
165; CHECK-VREG:    $rsi = COPY %1
166; CHECK-VREG:    CALL64pcrel32 @consume2, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit $rsi, implicit-def $rsp, implicit-def $ssp
167
168; CHECK-PREG-LABEL: name:            test_gcrelocate_uniqueing
169; CHECK-PREG:    renamable $rbx = COPY $rdi
170; 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
171; CHECK-PREG:    $rdi = COPY renamable $rbx
172; CHECK-PREG:    $rsi = COPY killed renamable $rbx
173; CHECK-PREG:    CALL64pcrel32 @consume2, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit killed $rsi, implicit-def $rsp, implicit-def $ssp
174
175  %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)]
176  %a = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %tok, i32 0, i32 0)
177  %b = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %tok, i32 1, i32 1)
178  call void @consume2(i32 addrspace(1)* %a, i32 addrspace(1)* %b)
179  ret void
180}
181
182; Two gc.relocates of a bitcasted pointer should only require a single spill/fill
183define void @test_gcptr_uniqueing(i32 addrspace(1)* %ptr) gc "statepoint-example" {
184; CHECK-VREG-LABEL: name:            test_gcptr_uniqueing
185; CHECK-VREG:    %0:gr64 = COPY $rdi
186; CHECK-VREG:    ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
187; 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
188; CHECK-VREG:    ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
189; CHECK-VREG:    ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
190; CHECK-VREG:    $rdi = COPY %1
191; CHECK-VREG:    $rsi = COPY %1
192; CHECK-VREG:    CALL64pcrel32 @use1, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit $rsi, implicit-def $rsp, implicit-def $ssp
193
194; CHECK-PREG-LABEL: name:            test_gcptr_uniqueing
195; CHECK-PREG:    renamable $rbx = COPY $rdi
196; 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
197; CHECK-PREG:    $rdi = COPY renamable $rbx
198; CHECK-PREG:    $rsi = COPY killed renamable $rbx
199; CHECK-PREG:    CALL64pcrel32 @use1, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit killed $rsi, implicit-def $rsp, implicit-def $ssp
200
201  %ptr2 = bitcast i32 addrspace(1)* %ptr to i8 addrspace(1)*
202  %tok = tail call token (i64, i32, void ()*, i32, i32, ...)
203      @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)]
204  %a = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %tok, i32 0, i32 0)
205  %b = call i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token %tok, i32 1, i32 1)
206  call void @use1(i32 addrspace(1)* %a, i8 addrspace(1)* %b)
207  ret void
208}
209
210define i1 @test_cross_bb(i32 addrspace(1)* %a, i1 %external_cond) gc "statepoint-example" {
211; CHECK-VREG-LABEL: name:            test_cross_bb
212; CHECK-VREG:  bb.0.entry:
213; CHECK-VREG:         %1:gr32 = COPY $esi
214; CHECK-VREG-NEXT:    %0:gr64 = COPY $rdi
215; CHECK-VREG-NEXT:    %4:gr8 = COPY %1.sub_8bit
216; CHECK-VREG-NEXT:    ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
217; 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
218; CHECK-VREG-NEXT:    ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
219; CHECK-VREG-NEXT:    %5:gr8 = COPY $al
220; CHECK-VREG-NEXT:    %3:gr8 = COPY %5
221; CHECK-VREG-NEXT:    TEST8ri killed %4, 1, implicit-def $eflags
222; CHECK-VREG-NEXT:    JCC_1 %bb.2, 4, implicit $eflags
223; CHECK-VREG-NEXT:    JMP_1 %bb.1
224; CHECK-VREG:       bb.1.left:
225; CHECK-VREG-NEXT:    ADJCALLSTACKDOWN64 0, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
226; CHECK-VREG-NEXT:    $rdi = COPY %2
227; CHECK-VREG-NEXT:    CALL64pcrel32 @consume, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit-def $rsp, implicit-def $ssp
228; CHECK-VREG-NEXT:    ADJCALLSTACKUP64 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
229; CHECK-VREG-NEXT:    $al = COPY %3
230; CHECK-VREG-NEXT:    RET 0, $al
231; CHECK-VREG:       bb.2.right:
232; CHECK-VREG-NEXT:    %6:gr8 = MOV8ri 1
233; CHECK-VREG-NEXT:    $al = COPY %6
234; CHECK-VREG-NEXT:    RET 0, $al
235
236entry:
237  %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)]
238  br i1 %external_cond, label %left, label %right
239
240left:
241  %call1 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 0, i32 0)
242  %call2 = call zeroext i1 @llvm.experimental.gc.result.i1(token %safepoint_token)
243  call void @consume(i32 addrspace(1)* %call1)
244  ret i1 %call2
245
246right:
247  ret i1 true
248}
249
250; No need to check post-regalloc output as it is the same
251define i1 @duplicate_reloc() gc "statepoint-example" {
252; CHECK-VREG-LABEL: name:            duplicate_reloc
253; CHECK-VREG:  bb.0.entry:
254; 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
255; 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
256; CHECK-VREG:    %0:gr8 = MOV8ri 1
257; CHECK-VREG:    $al = COPY %0
258; CHECK-VREG:    RET 0, $al
259
260entry:
261  %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)]
262  %base = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 0, i32 0)
263  %derived = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 0, i32 1)
264  %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)]
265  %base_reloc = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token2,  i32 0, i32 0)
266  %derived_reloc = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token2,  i32 0, i32 1)
267  %cmp1 = icmp eq i32 addrspace(1)* %base_reloc, null
268  %cmp2 = icmp eq i32 addrspace(1)* %derived_reloc, null
269  %cmp = and i1 %cmp1, %cmp2
270  ret i1 %cmp
271}
272
273; Vectors cannot go in VRegs
274; No need to check post-regalloc output as it is lowered using old scheme
275define <2 x i8 addrspace(1)*> @test_vector(<2 x i8 addrspace(1)*> %obj) gc "statepoint-example" {
276; CHECK-VREG-LABEL: name:            test_vector
277; CHECK-VREG:    %0:vr128 = COPY $xmm0
278; CHECK-VREG:    MOVAPSmr %stack.0, 1, $noreg, 0, $noreg, %0 :: (store 16 into %stack.0)
279; 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 16 on %stack.0)
280; CHECK-VREG:    %1:vr128 = MOVAPSrm %stack.0, 1, $noreg, 0, $noreg :: (load 16 from %stack.0)
281; CHECK-VREG:    $xmm0 = COPY %1
282; CHECK-VREG:    RET 0, $xmm0
283
284entry:
285  %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)]
286  %obj.relocated = call coldcc <2 x i8 addrspace(1)*> @llvm.experimental.gc.relocate.v2p1i8(token %safepoint_token, i32 0, i32 0) ; (%obj, %obj)
287  ret <2 x i8 addrspace(1)*> %obj.relocated
288}
289
290
291; test limit on amount of vregs
292define 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" {
293; CHECK-VREG-LABEL: name:            test_limit
294; CHECK-VREG:    %4:gr64 = COPY $r8
295; CHECK-VREG:    %3:gr64 = COPY $rcx
296; CHECK-VREG:    %2:gr64 = COPY $rdx
297; CHECK-VREG:    %1:gr64 = COPY $rsi
298; CHECK-VREG:    %0:gr64 = COPY $rdi
299; CHECK-VREG:    MOV64mr %stack.0, 1, $noreg, 0, $noreg, %0 :: (store 8 into %stack.0)
300; 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 8 on %stack.0)
301; CHECK-VREG:    %9:gr64 = MOV64rm %stack.0, 1, $noreg, 0, $noreg :: (load 8 from %stack.0)
302; CHECK-VREG:    $rdi = COPY %9
303; CHECK-VREG:    $rsi = COPY %8
304; CHECK-VREG:    $rdx = COPY %7
305; CHECK-VREG:    $rcx = COPY %6
306; CHECK-VREG:    $r8 = COPY %5
307; 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
308; CHECK-VREG:    RET 0
309entry:
310  %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)]
311  %rel1 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 0, i32 0)
312  %rel2 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 1, i32 1)
313  %rel3 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 2, i32 2)
314  %rel4 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 3, i32 3)
315  %rel5 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 4, i32 4)
316  call void @consume5(i32 addrspace(1)* %rel1, i32 addrspace(1)* %rel2, i32 addrspace(1)* %rel3, i32 addrspace(1)* %rel4, i32 addrspace(1)* %rel5)
317  ret void
318}
319
320; Different IR Values which maps to the same SDValue must be assigned to the same VReg.
321; This is test is similar to test_gcptr_uniqueing but explicitly uses invokes for which this is important
322; Otherwise we may get a copy of statepoint result, inserted at the end ot statepoint block and used at landing pad
323define void @test_duplicate_ir_values() gc "statepoint-example" personality i32* ()* @fake_personality_function{
324;CHECK-VREG-LABEL: name:            test_duplicate_ir_values
325;CHECK-VREG:   bb.0.entry:
326;CHECK-VREG:     %0:gr64 = STATEPOINT 1, 16, 5, %8, $edi, $rsi, $edx, $ecx, $r8d, 2, 0, 2, 0, 2, 0, 2, 1, killed %1(tied-def 0), 2, 0, 2, 1, 0, 0, csr_64, implicit-def $rsp, implicit-def $ssp, implicit-def $eax
327;CHECK-VREG:     JMP_1 %bb.1
328;CHECK-VREG:   bb.1.normal_continue:
329;CHECK-VREG:     MOV64mr %stack.0, 1, $noreg, 0, $noreg, %0 :: (store 8 into %stack.0)
330;CHECK-VREG:     %13:gr32 = MOV32ri 10
331;CHECK-VREG:     $edi = COPY %13
332;CHECK-VREG:     STATEPOINT 2882400000, 0, 1, @__llvm_deoptimize, $edi, 2, 0, 2, 2, 2, 2, 1, 8, %stack.0, 0, 1, 8, %stack.0, 0, 2, 0, 2, 0, 2, 0, csr_64, implicit-def $rsp, implicit-def $ssp :: (volatile load store 8 on %stack.0)
333;CHECK-VREG:   bb.2.exceptional_return (landing-pad):
334;CHECK-VREG:     EH_LABEL <mcsymbol >
335;CHECK-VREG:     MOV64mr %stack.0, 1, $noreg, 0, $noreg, %0 :: (store 8 into %stack.0)
336;CHECK-VREG:     %12:gr32 = MOV32ri -271
337;CHECK-VREG:     $edi = COPY %12
338;CHECK-VREG:     STATEPOINT 2882400000, 0, 1, @__llvm_deoptimize, $edi, 2, 0, 2, 0, 2, 1, 1, 8, %stack.0, 0, 2, 0, 2, 0, 2, 0, csr_64, implicit-def $rsp, implicit-def $ssp :: (volatile load store 8 on %stack.0)
339
340entry:
341  %local.0 = load i8 addrspace(1)*, i8 addrspace(1)* addrspace(1)* undef, align 8
342  %local.9 = load i8 addrspace(1)*, i8 addrspace(1)* addrspace(1)* undef, align 8
343  %statepoint_token1 = invoke token (i64, i32, i32 (i32, i8 addrspace(1)*, i32, i32, i32)*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i32i32p1i8i32i32i32f(i64 1, i32 16, i32 (i32, i8 addrspace(1)*, i32, i32, i32)* nonnull @foo, i32 5, i32 0, i32 undef, i8 addrspace(1)* undef, i32 undef, i32 undef, i32 undef, i32 0, i32 0) [ "deopt"(), "gc-live"(i8 addrspace(1)* %local.0, i8 addrspace(1)* %local.9) ]
344          to label %normal_continue unwind label %exceptional_return
345
346normal_continue: ; preds = %entry
347  %local.0.relocated1 = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token %statepoint_token1, i32 0, i32 0) ; (%local.0, %local.0)
348  %local.9.relocated1 = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token %statepoint_token1, i32 1, i32 1) ; (%local.9, %local.9)
349  %safepoint_token2 = call token (i64, i32, void (i32)*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidi32f(i64 2882400000, i32 0, void (i32)* nonnull @__llvm_deoptimize, i32 1, i32 2, i32 10, i32 0, i32 0) [ "deopt"(i8 addrspace(1)* %local.0.relocated1, i8 addrspace(1)* %local.9.relocated1), "gc-live"() ]
350  unreachable
351
352exceptional_return:                         ; preds = %entry
353  %lpad_token11090 = landingpad token
354          cleanup
355  %local.9.relocated2 = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token %lpad_token11090, i32 1, i32 1) ; (%local.9, %local.9)
356  %safepoint_token3 = call token (i64, i32, void (i32)*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidi32f(i64 2882400000, i32 0, void (i32)* nonnull @__llvm_deoptimize, i32 1, i32 0, i32 -271, i32 0, i32 0) [ "deopt"(i8 addrspace(1)* %local.9.relocated2), "gc-live"() ]
357  unreachable
358}
359
360; Test that CopyFromReg emitted during ISEL processing of gc.relocate are properly ordered w.r.t. statepoint.
361define i8 addrspace(1)* @test_isel_sched(i8 addrspace(1)* %0, i8 addrspace(1)* %1, i32 %2) gc "statepoint-example" {
362;CHECK-VREG-LABEL: name:            test_isel_sched
363;CHECK-VREG:  bb.0.entry:
364;CHECK-VREG:        %2:gr32 = COPY $edx
365;CHECK-VREG:        %1:gr64 = COPY $rsi
366;CHECK-VREG:        %0:gr64 = COPY $rdi
367;CHECK-VREG:        TEST32rr %2, %2, implicit-def $eflags
368;CHECK-VREG:        %5:gr64 = CMOV64rr %1, %0, 4, implicit $eflags
369;CHECK-VREG:        %6:gr32 = MOV32r0 implicit-def dead $eflags
370;CHECK-VREG:        %7:gr64 = SUBREG_TO_REG 0, killed %6, %subreg.sub_32bit
371;CHECK-VREG:        $rdi = COPY %7
372;CHECK-VREG:        $rsi = COPY %5
373;CHECK-VREG:        %3:gr64, %4: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
374;CHECK-VREG:        TEST32rr %2, %2, implicit-def $eflags
375;CHECK-VREG:        %8:gr64 = CMOV64rr %3, %4, 4, implicit $eflags
376;CHECK-VREG:        $rax = COPY %8
377;CHECK-VREG:        RET 0, $rax
378entry:
379  %cmp = icmp eq i32 %2, 0
380  %ptr = select i1 %cmp, i8 addrspace(1)* %0, i8 addrspace(1)* %1
381  %token = call token (i64, i32, void (i8 addrspace(1)*, i8 addrspace(1)*)*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidp1i8p1i8f(i64 10, i32 0, void (i8 addrspace(1)*, i8 addrspace(1)*)* @bar, i32 2, i32 0, i8 addrspace(1)* null, i8 addrspace(1)* %ptr, i32 0, i32 0) [ "deopt"(), "gc-live"(i8 addrspace(1)* %0, i8 addrspace(1)* %1) ]
382  %rel0 = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token %token, i32 0, i32 0)
383  %rel1 = call coldcc i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token %token, i32 1, i32 1)
384  %res = select i1 %cmp, i8 addrspace(1)* %rel0, i8 addrspace(1)* %rel1
385  ret i8 addrspace(1)* %res
386}
387
388declare token @llvm.experimental.gc.statepoint.p0f_i1f(i64, i32, i1 ()*, i32, i32, ...)
389declare token @llvm.experimental.gc.statepoint.p0f_isVoidf(i64, i32, void ()*, i32, i32, ...)
390declare dso_local i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token, i32, i32)
391declare dso_local i8 addrspace(1)* @llvm.experimental.gc.relocate.p1i8(token, i32, i32)
392declare <2 x i8 addrspace(1)*> @llvm.experimental.gc.relocate.v2p1i8(token, i32, i32)
393declare dso_local i1 @llvm.experimental.gc.result.i1(token)
394declare dso_local void @__llvm_deoptimize(i32)
395declare token @llvm.experimental.gc.statepoint.p0f_isVoidi32f(i64 immarg, i32 immarg, void (i32)*, i32 immarg, i32 immarg, ...)
396declare token @llvm.experimental.gc.statepoint.p0f_i32i32p1i8i32i32i32f(i64 immarg, i32 immarg, i32 (i32, i8 addrspace(1)*, i32, i32, i32)*, i32 immarg, i32 immarg, ...)
397declare token @llvm.experimental.gc.statepoint.p0f_isVoidp1i8p1i8f(i64 immarg, i32 immarg, void (i8 addrspace(1)*, i8 addrspace(1)*)*, i32 immarg, i32 immarg, ...)
398
399