• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1; RUN: llc -verify-machineinstrs < %s | FileCheck %s
2; This file contains a collection of basic tests to ensure we didn't
3; screw up normal call lowering when there are no deopt or gc arguments.
4
5target datalayout = "e-i64:64-f80:128-n8:16:32:64-S128"
6target triple = "x86_64-pc-linux-gnu"
7
8%struct = type { i64, i64 }
9
10declare zeroext i1 @return_i1()
11declare zeroext i32 @return_i32()
12declare i32* @return_i32ptr()
13declare float @return_float()
14declare %struct @return_struct()
15declare void @varargf(i32, ...)
16
17define i1 @test_i1_return() gc "statepoint-example" {
18; CHECK-LABEL: test_i1_return
19; This is just checking that a i1 gets lowered normally when there's no extra
20; state arguments to the statepoint
21; CHECK: pushq %rax
22; CHECK: callq return_i1
23; CHECK: popq %rcx
24; CHECK: retq
25entry:
26  %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)
27  %call1 = call zeroext i1 @llvm.experimental.gc.result.i1(token %safepoint_token)
28  ret i1 %call1
29}
30
31define i32 @test_i32_return() gc "statepoint-example" {
32; CHECK-LABEL: test_i32_return
33; CHECK: pushq %rax
34; CHECK: callq return_i32
35; CHECK: popq %rcx
36; CHECK: retq
37entry:
38  %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)
39  %call1 = call zeroext i32 @llvm.experimental.gc.result.i32(token %safepoint_token)
40  ret i32 %call1
41}
42
43define i32* @test_i32ptr_return() gc "statepoint-example" {
44; CHECK-LABEL: test_i32ptr_return
45; CHECK: pushq %rax
46; CHECK: callq return_i32ptr
47; CHECK: popq %rcx
48; CHECK: retq
49entry:
50  %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)
51  %call1 = call i32* @llvm.experimental.gc.result.p0i32(token %safepoint_token)
52  ret i32* %call1
53}
54
55define float @test_float_return() gc "statepoint-example" {
56; CHECK-LABEL: test_float_return
57; CHECK: pushq %rax
58; CHECK: callq return_float
59; CHECK: popq %rax
60; CHECK: retq
61entry:
62  %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)
63  %call1 = call float @llvm.experimental.gc.result.f32(token %safepoint_token)
64  ret float %call1
65}
66
67define %struct @test_struct_return() gc "statepoint-example" {
68; CHECK-LABEL: test_struct_return
69; CHECK: pushq %rax
70; CHECK: callq return_struct
71; CHECK: popq %rcx
72; CHECK: retq
73entry:
74  %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)
75  %call1 = call %struct @llvm.experimental.gc.result.struct(token %safepoint_token)
76  ret %struct %call1
77}
78
79define i1 @test_relocate(i32 addrspace(1)* %a) gc "statepoint-example" {
80; CHECK-LABEL: test_relocate
81; Check that an ununsed relocate has no code-generation impact
82; CHECK: pushq %rax
83; CHECK: callq return_i1
84; CHECK-NEXT: .Ltmp5:
85; CHECK-NEXT: popq %rcx
86; CHECK-NEXT: .cfi_def_cfa_offset 8
87; CHECK-NEXT: retq
88entry:
89  %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, i32 addrspace(1)* %a)
90  %call1 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 7, i32 7)
91  %call2 = call zeroext i1 @llvm.experimental.gc.result.i1(token %safepoint_token)
92  ret i1 %call2
93}
94
95define void @test_void_vararg() gc "statepoint-example" {
96; CHECK-LABEL: test_void_vararg
97; Check a statepoint wrapping a *void* returning vararg function works
98; CHECK: callq varargf
99entry:
100  %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)
101  ;; if we try to use the result from a statepoint wrapping a
102  ;; non-void-returning varargf, we will experience a crash.
103  ret void
104}
105
106define i1 @test_i1_return_patchable() gc "statepoint-example" {
107; CHECK-LABEL: test_i1_return_patchable
108; A patchable variant of test_i1_return
109; CHECK: pushq %rax
110; CHECK: nopl
111; CHECK: popq %rcx
112; CHECK: retq
113entry:
114  %safepoint_token = tail call token (i64, i32, i1 ()*, i32, i32, ...) @llvm.experimental.gc.statepoint.p0f_i1f(i64 0, i32 3, i1 ()*null, i32 0, i32 0, i32 0, i32 0)
115  %call1 = call zeroext i1 @llvm.experimental.gc.result.i1(token %safepoint_token)
116  ret i1 %call1
117}
118
119declare void @consume(i32 addrspace(1)* %obj)
120
121define i1 @test_cross_bb(i32 addrspace(1)* %a, i1 %external_cond) gc "statepoint-example" {
122; CHECK-LABEL: test_cross_bb
123; CHECK: movq
124; CHECK: callq return_i1
125; CHECK: %left
126; CHECK: movq
127; CHECK-NEXT: callq consume
128; CHECK: retq
129entry:
130  %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, i32 addrspace(1)* %a)
131  br i1 %external_cond, label %left, label %right
132
133left:
134  %call1 = call i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token %safepoint_token,  i32 7, i32 7)
135  %call2 = call zeroext i1 @llvm.experimental.gc.result.i1(token %safepoint_token)
136  call void @consume(i32 addrspace(1)* %call1)
137  ret i1 %call2
138
139right:
140  ret i1 true
141}
142
143%struct2 = type { i64, i64, i64 }
144
145declare void @consume_attributes(i32, i8* nest, i32, %struct2* byval)
146
147define void @test_attributes(%struct2* byval %s) gc "statepoint-example" {
148entry:
149; CHECK-LABEL: test_attributes
150; Check that arguments with attributes are lowered correctly.
151; We call a function that has a nest argument and a byval argument.
152; CHECK: movl $42, %edi
153; CHECK: xorl %r10d, %r10d
154; CHECK: movl $17, %esi
155; CHECK: pushq
156; CHECK: pushq
157; CHECK: pushq
158; CHECK: callq consume_attributes
159  %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 %s, i32 0, i32 0)
160  ret void
161}
162
163declare token @llvm.experimental.gc.statepoint.p0f_i1f(i64, i32, i1 ()*, i32, i32, ...)
164declare i1 @llvm.experimental.gc.result.i1(token)
165
166declare token @llvm.experimental.gc.statepoint.p0f_i32f(i64, i32, i32 ()*, i32, i32, ...)
167declare i32 @llvm.experimental.gc.result.i32(token)
168
169declare token @llvm.experimental.gc.statepoint.p0f_p0i32f(i64, i32, i32* ()*, i32, i32, ...)
170declare i32* @llvm.experimental.gc.result.p0i32(token)
171
172declare token @llvm.experimental.gc.statepoint.p0f_f32f(i64, i32, float ()*, i32, i32, ...)
173declare float @llvm.experimental.gc.result.f32(token)
174
175declare token @llvm.experimental.gc.statepoint.p0f_structf(i64, i32, %struct ()*, i32, i32, ...)
176declare %struct @llvm.experimental.gc.result.struct(token)
177
178declare token @llvm.experimental.gc.statepoint.p0f_isVoidi32varargf(i64, i32, void (i32, ...)*, i32, i32, ...)
179
180declare token @llvm.experimental.gc.statepoint.p0f_isVoidi32p0i8i32p0s_struct2sf(i64, i32, void (i32, i8*, i32, %struct2*)*, i32, i32, ...)
181
182declare i32 addrspace(1)* @llvm.experimental.gc.relocate.p1i32(token, i32, i32)
183