• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1; RUN: llc < %s -asm-verbose=false -verify-machineinstrs -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -mattr=+tail-call | FileCheck --check-prefixes=CHECK,SLOW %s
2; RUN: llc < %s -asm-verbose=false -verify-machineinstrs -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -fast-isel -mattr=+tail-call | FileCheck --check-prefixes=CHECK,FAST %s
3; RUN: llc < %s --filetype=obj -mattr=+tail-call | obj2yaml | FileCheck --check-prefix=YAML %s
4
5; Test that the tail calls lower correctly
6
7target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
8target triple = "wasm32-unknown-unknown"
9
10%fn = type <{i32 (%fn, i32, i32)*}>
11declare i1 @foo(i1)
12declare i1 @bar(i1)
13
14; CHECK-LABEL: recursive_notail_nullary:
15; CHECK: {{^}} call recursive_notail_nullary{{$}}
16; CHECK-NEXT: return
17define void @recursive_notail_nullary() {
18  notail call void @recursive_notail_nullary()
19  ret void
20}
21
22; CHECK-LABEL: recursive_musttail_nullary:
23; CHECK: return_call recursive_musttail_nullary{{$}}
24define void @recursive_musttail_nullary() {
25  musttail call void @recursive_musttail_nullary()
26  ret void
27}
28
29; CHECK-LABEL: recursive_tail_nullary:
30; SLOW: return_call recursive_tail_nullary{{$}}
31; FAST: {{^}} call recursive_tail_nullary{{$}}
32; FAST-NEXT: return{{$}}
33define void @recursive_tail_nullary() {
34  tail call void @recursive_tail_nullary()
35  ret void
36}
37
38; CHECK-LABEL: recursive_notail:
39; CHECK: call $push[[L:[0-9]+]]=, recursive_notail, $0, $1{{$}}
40; CHECK-NEXT: return $pop[[L]]{{$}}
41define i32 @recursive_notail(i32 %x, i32 %y) {
42  %v = notail call i32 @recursive_notail(i32 %x, i32 %y)
43  ret i32 %v
44}
45
46; CHECK-LABEL: recursive_musttail:
47; CHECK: return_call recursive_musttail, $0, $1{{$}}
48define i32 @recursive_musttail(i32 %x, i32 %y) {
49  %v = musttail call i32 @recursive_musttail(i32 %x, i32 %y)
50  ret i32 %v
51}
52
53; CHECK-LABEL: recursive_tail:
54; SLOW: return_call recursive_tail, $0, $1{{$}}
55; FAST: call $push[[L:[0-9]+]]=, recursive_tail, $0, $1{{$}}
56; FAST-NEXT: return $pop[[L]]{{$}}
57define i32 @recursive_tail(i32 %x, i32 %y) {
58  %v = tail call i32 @recursive_tail(i32 %x, i32 %y)
59  ret i32 %v
60}
61
62; CHECK-LABEL: indirect_notail:
63; CHECK: call_indirect $push[[L:[0-9]+]]=, $0, $1, $2, $0{{$}}
64; CHECK-NEXT: return $pop[[L]]{{$}}
65define i32 @indirect_notail(%fn %f, i32 %x, i32 %y) {
66  %p = extractvalue %fn %f, 0
67  %v = notail call i32 %p(%fn %f, i32 %x, i32 %y)
68  ret i32 %v
69}
70
71; CHECK-LABEL: indirect_musttail:
72; CHECK: return_call_indirect , $0, $1, $2, $0{{$}}
73define i32 @indirect_musttail(%fn %f, i32 %x, i32 %y) {
74  %p = extractvalue %fn %f, 0
75  %v = musttail call i32 %p(%fn %f, i32 %x, i32 %y)
76  ret i32 %v
77}
78
79; CHECK-LABEL: indirect_tail:
80; CHECK: return_call_indirect , $0, $1, $2, $0{{$}}
81define i32 @indirect_tail(%fn %f, i32 %x, i32 %y) {
82  %p = extractvalue %fn %f, 0
83  %v = tail call i32 %p(%fn %f, i32 %x, i32 %y)
84  ret i32 %v
85}
86
87; CHECK-LABEL: choice_notail:
88; CHECK: call_indirect $push[[L:[0-9]+]]=, $0, $pop{{[0-9]+}}{{$}}
89; CHECK-NEXT: return $pop[[L]]{{$}}
90define i1 @choice_notail(i1 %x) {
91  %p = select i1 %x, i1 (i1)* @foo, i1 (i1)* @bar
92  %v = notail call i1 %p(i1 %x)
93  ret i1 %v
94}
95
96; CHECK-LABEL: choice_musttail:
97; CHECK: return_call_indirect , $0, $pop{{[0-9]+}}{{$}}
98define i1 @choice_musttail(i1 %x) {
99  %p = select i1 %x, i1 (i1)* @foo, i1 (i1)* @bar
100  %v = musttail call i1 %p(i1 %x)
101  ret i1 %v
102}
103
104; CHECK-LABEL: choice_tail:
105; SLOW: return_call_indirect , $0, $pop{{[0-9]+}}{{$}}
106; FAST: call_indirect $push[[L:[0-9]+]]=, $0, $pop{{[0-9]+}}{{$}}
107; FAST: return $pop[[L]]{{$}}
108define i1 @choice_tail(i1 %x) {
109  %p = select i1 %x, i1 (i1)* @foo, i1 (i1)* @bar
110  %v = tail call i1 %p(i1 %x)
111  ret i1 %v
112}
113
114; It is an LLVM validation error for a 'musttail' callee to have a different
115; prototype than its caller, so the following tests can only be done with
116; 'tail'.
117
118; CHECK-LABEL: mismatched_prototypes:
119; SLOW: return_call baz, $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
120; FAST: call $push[[L:[0-9]+]]=, baz, $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
121; FAST: return $pop[[L]]{{$}}
122declare i32 @baz(i32, i32, i32)
123define i32 @mismatched_prototypes() {
124  %v = tail call i32 @baz(i32 0, i32 42, i32 6)
125  ret i32 %v
126}
127
128; CHECK-LABEL: mismatched_return_void:
129; CHECK: call $drop=, baz, $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
130; CHECK: return{{$}}
131define void @mismatched_return_void() {
132  %v = tail call i32 @baz(i32 0, i32 42, i32 6)
133  ret void
134}
135
136; CHECK-LABEL: mismatched_return_f32:
137; CHECK: call $push[[L:[0-9]+]]=, baz, $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
138; CHECK: f32.reinterpret_i32 $push[[L1:[0-9]+]]=, $pop[[L]]{{$}}
139; CHECK: return $pop[[L1]]{{$}}
140define float @mismatched_return_f32() {
141  %v = tail call i32 @baz(i32 0, i32 42, i32 6)
142  %u = bitcast i32 %v to float
143  ret float %u
144}
145
146; CHECK-LABEL: mismatched_indirect_void:
147; CHECK: call_indirect $drop=, $0, $1, $2, $0{{$}}
148; CHECK: return{{$}}
149define void @mismatched_indirect_void(%fn %f, i32 %x, i32 %y) {
150  %p = extractvalue %fn %f, 0
151  %v = tail call i32 %p(%fn %f, i32 %x, i32 %y)
152  ret void
153}
154
155; CHECK-LABEL: mismatched_indirect_f32:
156; CHECK: call_indirect $push[[L:[0-9]+]]=, $0, $1, $2, $0{{$}}
157; CHECK: f32.reinterpret_i32 $push[[L1:[0-9]+]]=, $pop[[L]]{{$}}
158; CHECK: return $pop[[L1]]{{$}}
159define float @mismatched_indirect_f32(%fn %f, i32 %x, i32 %y) {
160  %p = extractvalue %fn %f, 0
161  %v = tail call i32 %p(%fn %f, i32 %x, i32 %y)
162  %u = bitcast i32 %v to float
163  ret float %u
164}
165
166; CHECK-LABEL: mismatched_byval:
167; CHECK: i32.store
168; CHECK: return_call quux, $pop{{[0-9]+}}{{$}}
169declare i32 @quux(i32* byval(i32))
170define i32 @mismatched_byval(i32* %x) {
171  %v = tail call i32 @quux(i32* byval(i32) %x)
172  ret i32 %v
173}
174
175; CHECK-LABEL: varargs:
176; CHECK: i32.store
177; CHECK: call $0=, var, $1{{$}}
178; CHECK: return $0{{$}}
179declare i32 @var(...)
180define i32 @varargs(i32 %x) {
181  %v = tail call i32 (...) @var(i32 %x)
182  ret i32 %v
183}
184
185; Type transformations inhibit tail calls, even when they are nops
186
187; CHECK-LABEL: mismatched_return_zext:
188; CHECK: call
189define i32 @mismatched_return_zext() {
190  %v = tail call i1 @foo(i1 1)
191  %u = zext i1 %v to i32
192  ret i32 %u
193}
194
195; CHECK-LABEL: mismatched_return_sext:
196; CHECK: call
197define i32 @mismatched_return_sext() {
198  %v = tail call i1 @foo(i1 1)
199  %u = sext i1 %v to i32
200  ret i32 %u
201}
202
203; CHECK-LABEL: mismatched_return_trunc:
204; CHECK: call
205declare i32 @int()
206define i1 @mismatched_return_trunc() {
207  %v = tail call i32 @int()
208  %u = trunc i32 %v to i1
209  ret i1 %u
210}
211
212; Stack-allocated arguments inhibit tail calls
213
214; CHECK-LABEL: stack_arg:
215; CHECK: call
216define i32 @stack_arg(i32* %x) {
217  %a = alloca i32
218  %v = tail call i32 @stack_arg(i32* %a)
219  ret i32 %v
220}
221
222; CHECK-LABEL: stack_arg_gep:
223; CHECK: call
224define i32 @stack_arg_gep(i32* %x) {
225  %a = alloca { i32, i32 }
226  %p = getelementptr { i32, i32 }, { i32, i32 }* %a, i32 0, i32 1
227  %v = tail call i32 @stack_arg_gep(i32* %p)
228  ret i32 %v
229}
230
231; CHECK-LABEL: stack_arg_cast:
232; CHECK: global.get $push{{[0-9]+}}=, __stack_pointer
233; CHECK: global.set __stack_pointer, $pop{{[0-9]+}}
234; FAST: call ${{[0-9]+}}=, stack_arg_cast, $pop{{[0-9]+}}
235; CHECK: global.set __stack_pointer, $pop{{[0-9]+}}
236; SLOW: return_call stack_arg_cast, ${{[0-9]+}}
237define i32 @stack_arg_cast(i32 %x) {
238  %a = alloca [64 x i32]
239  %i = ptrtoint [64 x i32]* %a to i32
240  %v = tail call i32 @stack_arg_cast(i32 %i)
241  ret i32 %v
242}
243
244; Check that the signatures generated for external indirectly
245; return-called functions include the proper return types
246
247; YAML-LABEL: - Index:           8
248; YAML-NEXT:    ParamTypes:
249; YAML-NEXT:      - I32
250; YAML-NEXT:      - F32
251; YAML-NEXT:      - I64
252; YAML-NEXT:      - F64
253; YAML-NEXT:    ReturnTypes:
254; YAML-NEXT:      - I32
255define i32 @unique_caller(i32 (i32, float, i64, double)** %p) {
256  %f = load i32 (i32, float, i64, double)*, i32 (i32, float, i64, double)** %p
257  %v = tail call i32 %f(i32 0, float 0., i64 0, double 0.)
258  ret i32 %v
259}
260
261; CHECK-LABEL: .section .custom_section.target_features
262; CHECK-NEXT: .int8 1
263; CHECK-NEXT: .int8 43
264; CHECK-NEXT: .int8 9
265; CHECK-NEXT: .ascii "tail-call"
266