1 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2 ; RUN: llc -verify-machineinstrs < %s | FileCheck %s
3 ; A collection of basic functionality tests for statepoint lowering - most
4 ; interesting cornercases are exercised through the x86 tests.
6 target datalayout = "e-i64:64-f80:128-n8:16:32:64-S128"
7 target triple = "aarch64-unknown-linux-gnu"
9 %struct = type { i64, i64 }
11 declare zeroext i1 @return_i1()
12 declare zeroext i32 @return_i32()
13 declare i32* @return_i32ptr()
14 declare float @return_float()
15 declare %struct @return_struct()
16 declare void @varargf(i32, ...)
18 define i1 @test_i1_return() gc "statepoint-example" {
19 ; CHECK-LABEL: test_i1_return:
20 ; CHECK: // %bb.0: // %entry
21 ; CHECK-NEXT: bl return_i1
23 ; CHECK-NEXT: and w0, w0, #0x1
25 ; This is just checking that a i1 gets lowered normally when there's no extra
26 ; state arguments to the statepoint
28 %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)
29 %call1 = call zeroext i1 @llvm.experimental.gc.result.i1(token %safepoint_token)
33 define i32 @test_i32_return() gc "statepoint-example" {
34 ; CHECK-LABEL: test_i32_return:
35 ; CHECK: // %bb.0: // %entry
36 ; CHECK-NEXT: bl return_i32
40 %safepoint_token = tail call token (i64, i32, i32 ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i32f(i64 0, i32 0, i32 ()* @return_i32, i32 0, i32 0, i32 0, i32 0)
41 %call1 = call zeroext i32 @llvm.experimental.gc.result.i32(token %safepoint_token)
45 define i32* @test_i32ptr_return() gc "statepoint-example" {
46 ; CHECK-LABEL: test_i32ptr_return:
47 ; CHECK: // %bb.0: // %entry
48 ; CHECK-NEXT: bl return_i32ptr
52 %safepoint_token = tail call token (i64, i32, i32* ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_p0i32f(i64 0, i32 0, i32* ()* @return_i32ptr, i32 0, i32 0, i32 0, i32 0)
53 %call1 = call i32* @llvm.experimental.gc.result.p0i32(token %safepoint_token)
57 define float @test_float_return() gc "statepoint-example" {
58 ; CHECK-LABEL: test_float_return:
59 ; CHECK: // %bb.0: // %entry
60 ; CHECK-NEXT: bl return_float
64 %safepoint_token = tail call token (i64, i32, float ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_f32f(i64 0, i32 0, float ()* @return_float, i32 0, i32 0, i32 0, i32 0)
65 %call1 = call float @llvm.experimental.gc.result.f32(token %safepoint_token)
69 define %struct @test_struct_return() gc "statepoint-example" {
70 ; CHECK-LABEL: test_struct_return:
71 ; CHECK: // %bb.0: // %entry
72 ; CHECK-NEXT: bl return_struct
76 %safepoint_token = tail call token (i64, i32, %struct ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_structf(i64 0, i32 0, %struct ()* @return_struct, i32 0, i32 0, i32 0, i32 0)
77 %call1 = call %struct @llvm.experimental.gc.result.struct(token %safepoint_token)
81 define i1 @test_relocate(i32 addrspace(1)* %a) gc "statepoint-example" {
82 ; CHECK-LABEL: test_relocate:
83 ; CHECK: // %bb.0: // %entry
84 ; CHECK-NEXT: sub sp, sp, #16
85 ; CHECK-NEXT: .cfi_def_cfa_offset 16
86 ; CHECK-NEXT: str x0, [sp, #8]
87 ; CHECK-NEXT: bl return_i1
89 ; CHECK-NEXT: and w0, w0, #0x1
90 ; CHECK-NEXT: add sp, sp, #16
92 ; Check that an ununsed relocate has no code-generation impact
94 %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)]
95 %call1 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 0, i32 0)
96 %call2 = call zeroext i1 @llvm.experimental.gc.result.i1(token %safepoint_token)
100 define void @test_void_vararg() gc "statepoint-example" {
101 ; CHECK-LABEL: test_void_vararg:
102 ; CHECK: // %bb.0: // %entry
103 ; CHECK-NEXT: mov w0, #42
104 ; CHECK-NEXT: mov w1, #43
105 ; CHECK-NEXT: bl varargf
106 ; CHECK-NEXT: .Ltmp8:
108 ; Check a statepoint wrapping a *void* returning vararg function works
110 %safepoint_token = tail call token (i64, i32, void (i32, ...)*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidi32varargf(i64 0, i32 0, void (i32, ...)* @varargf, i32 2, i32 0, i32 42, i32 43, i32 0, i32 0)
111 ;; if we try to use the result from a statepoint wrapping a
112 ;; non-void-returning varargf, we will experience a crash.
116 define i1 @test_i1_return_patchable() gc "statepoint-example" {
117 ; CHECK-LABEL: test_i1_return_patchable:
118 ; CHECK: // %bb.0: // %entry
120 ; CHECK-NEXT: .Ltmp9:
121 ; CHECK-NEXT: and w0, w0, #0x1
123 ; A patchable variant of test_i1_return
125 %safepoint_token = tail call token (i64, i32, i1 ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i1f(i64 0, i32 4, i1 ()*null, i32 0, i32 0, i32 0, i32 0)
126 %call1 = call zeroext i1 @llvm.experimental.gc.result.i1(token %safepoint_token)
130 declare void @consume(i32 addrspace(1)* %obj)
132 define i1 @test_cross_bb(i32 addrspace(1)* %a, i1 %external_cond) gc "statepoint-example" {
133 ; CHECK-LABEL: test_cross_bb:
134 ; CHECK: // %bb.0: // %entry
135 ; CHECK-NEXT: str x30, [sp, #-32]! // 8-byte Folded Spill
136 ; CHECK-NEXT: stp x20, x19, [sp, #16] // 16-byte Folded Spill
137 ; CHECK-NEXT: .cfi_def_cfa_offset 32
138 ; CHECK-NEXT: .cfi_offset w19, -8
139 ; CHECK-NEXT: .cfi_offset w20, -16
140 ; CHECK-NEXT: .cfi_offset w30, -32
141 ; CHECK-NEXT: mov w20, w1
142 ; CHECK-NEXT: str x0, [sp, #8]
143 ; CHECK-NEXT: bl return_i1
144 ; CHECK-NEXT: .Ltmp10:
145 ; CHECK-NEXT: tbz w20, #0, .LBB8_2
146 ; CHECK-NEXT: // %bb.1: // %left
147 ; CHECK-NEXT: mov w19, w0
148 ; CHECK-NEXT: ldr x0, [sp, #8]
149 ; CHECK-NEXT: bl consume
150 ; CHECK-NEXT: b .LBB8_3
151 ; CHECK-NEXT: .LBB8_2:
152 ; CHECK-NEXT: mov w19, #1
153 ; CHECK-NEXT: .LBB8_3: // %common.ret
154 ; CHECK-NEXT: and w0, w19, #0x1
155 ; CHECK-NEXT: ldp x20, x19, [sp, #16] // 16-byte Folded Reload
156 ; CHECK-NEXT: ldr x30, [sp], #32 // 8-byte Folded Reload
159 %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)]
160 br i1 %external_cond, label %left, label %right
163 %call1 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token, i32 0, i32 0)
164 %call2 = call zeroext i1 @llvm.experimental.gc.result.i1(token %safepoint_token)
165 call void @consume(i32 addrspace(1)* %call1)
172 %struct2 = type { i64, i64, i64 }
174 declare void @consume_attributes(i32, i8* nest, i32, %struct2* byval(%struct2))
176 define void @test_attributes(%struct2* byval(%struct2) %s) gc "statepoint-example" {
177 ; CHECK-LABEL: test_attributes:
178 ; CHECK: // %bb.0: // %entry
179 ; CHECK-NEXT: sub sp, sp, #32
180 ; CHECK-NEXT: .cfi_def_cfa_offset 32
181 ; CHECK-NEXT: ldr x8, [sp, #48]
182 ; CHECK-NEXT: ldr q0, [sp, #32]
183 ; CHECK-NEXT: mov w0, #42
184 ; CHECK-NEXT: mov w1, #17
185 ; CHECK-NEXT: mov x18, xzr
186 ; CHECK-NEXT: str x8, [sp, #16]
187 ; CHECK-NEXT: str q0, [sp]
188 ; CHECK-NEXT: bl consume_attributes
189 ; CHECK-NEXT: .Ltmp11:
190 ; CHECK-NEXT: add sp, sp, #32
193 ; Check that arguments with attributes are lowered correctly.
194 ; We call a function that has a nest argument and a byval argument.
195 %statepoint_token = call token (i64, i32, void (i32, i8*, i32, %struct2*)*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_isVoidi32p0i8i32p0s_struct2sf(i64 0, i32 0, void (i32, i8*, i32, %struct2*)* @consume_attributes, i32 4, i32 0, i32 42, i8* nest null, i32 17, %struct2* byval(%struct2) %s, i32 0, i32 0)
199 declare token @llvm.experimental.gc.statepoint.p0f_i1f(i64, i32, i1 ()*, i32, i32, ...)
200 declare i1 @llvm.experimental.gc.result.i1(token)
202 declare token @llvm.experimental.gc.statepoint.p0f_i32f(i64, i32, i32 ()*, i32, i32, ...)
203 declare i32 @llvm.experimental.gc.result.i32(token)
205 declare token @llvm.experimental.gc.statepoint.p0f_p0i32f(i64, i32, i32* ()*, i32, i32, ...)
206 declare i32* @llvm.experimental.gc.result.p0i32(token)
208 declare token @llvm.experimental.gc.statepoint.p0f_f32f(i64, i32, float ()*, i32, i32, ...)
209 declare float @llvm.experimental.gc.result.f32(token)
211 declare token @llvm.experimental.gc.statepoint.p0f_structf(i64, i32, %struct ()*, i32, i32, ...)
212 declare %struct @llvm.experimental.gc.result.struct(token)
214 declare token @llvm.experimental.gc.statepoint.p0f_isVoidi32varargf(i64, i32, void (i32, ...)*, i32, i32, ...)
216 declare token @llvm.experimental.gc.statepoint.p0f_isVoidi32p0i8i32p0s_struct2sf(i64, i32, void (i32, i8*, i32, %struct2*)*, i32, i32, ...)
218 declare i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token, i32, i32)