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
5 ; Test that the tail calls lower correctly
7 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
8 target triple = "wasm32-unknown-unknown"
10 %fn = type <{i32 (%fn, i32, i32)*}>
14 ; CHECK-LABEL: recursive_notail_nullary:
15 ; CHECK: {{^}} call recursive_notail_nullary{{$}}
17 define void @recursive_notail_nullary() {
18 notail call void @recursive_notail_nullary()
22 ; CHECK-LABEL: recursive_musttail_nullary:
23 ; CHECK: return_call recursive_musttail_nullary{{$}}
24 define void @recursive_musttail_nullary() {
25 musttail call void @recursive_musttail_nullary()
29 ; CHECK-LABEL: recursive_tail_nullary:
30 ; SLOW: return_call recursive_tail_nullary{{$}}
31 ; FAST: {{^}} call recursive_tail_nullary{{$}}
32 ; FAST-NEXT: return{{$}}
33 define void @recursive_tail_nullary() {
34 tail call void @recursive_tail_nullary()
38 ; CHECK-LABEL: recursive_notail:
39 ; CHECK: i32.call $push[[L:[0-9]+]]=, recursive_notail, $0, $1{{$}}
40 ; CHECK-NEXT: return $pop[[L]]{{$}}
41 define i32 @recursive_notail(i32 %x, i32 %y) {
42 %v = notail call i32 @recursive_notail(i32 %x, i32 %y)
46 ; CHECK-LABEL: recursive_musttail:
47 ; CHECK: return_call recursive_musttail, $0, $1{{$}}
48 define i32 @recursive_musttail(i32 %x, i32 %y) {
49 %v = musttail call i32 @recursive_musttail(i32 %x, i32 %y)
53 ; CHECK-LABEL: recursive_tail:
54 ; SLOW: return_call recursive_tail, $0, $1{{$}}
55 ; FAST: i32.call $push[[L:[0-9]+]]=, recursive_tail, $0, $1{{$}}
56 ; FAST-NEXT: return $pop[[L]]{{$}}
57 define i32 @recursive_tail(i32 %x, i32 %y) {
58 %v = tail call i32 @recursive_tail(i32 %x, i32 %y)
62 ; CHECK-LABEL: indirect_notail:
63 ; CHECK: i32.call_indirect $push[[L:[0-9]+]]=, $0, $1, $2, $0{{$}}
64 ; CHECK-NEXT: return $pop[[L]]{{$}}
65 define 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)
71 ; CHECK-LABEL: indirect_musttail:
72 ; CHECK: return_call_indirect , $0, $1, $2, $0{{$}}
73 define 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)
79 ; CHECK-LABEL: indirect_tail:
80 ; CHECK: return_call_indirect , $0, $1, $2, $0{{$}}
81 define 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)
87 ; CHECK-LABEL: choice_notail:
88 ; CHECK: i32.call_indirect $push[[L:[0-9]+]]=, $0, $pop{{[0-9]+}}{{$}}
89 ; CHECK-NEXT: return $pop[[L]]{{$}}
90 define i1 @choice_notail(i1 %x) {
91 %p = select i1 %x, i1 (i1)* @foo, i1 (i1)* @bar
92 %v = notail call i1 %p(i1 %x)
96 ; CHECK-LABEL: choice_musttail:
97 ; CHECK: return_call_indirect , $0, $pop{{[0-9]+}}{{$}}
98 define i1 @choice_musttail(i1 %x) {
99 %p = select i1 %x, i1 (i1)* @foo, i1 (i1)* @bar
100 %v = musttail call i1 %p(i1 %x)
104 ; CHECK-LABEL: choice_tail:
105 ; SLOW: return_call_indirect , $0, $pop{{[0-9]+}}{{$}}
106 ; FAST: i32.call_indirect $push[[L:[0-9]+]]=, $0, $pop{{[0-9]+}}{{$}}
107 ; FAST: return $pop[[L]]{{$}}
108 define i1 @choice_tail(i1 %x) {
109 %p = select i1 %x, i1 (i1)* @foo, i1 (i1)* @bar
110 %v = tail call i1 %p(i1 %x)
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
118 ; CHECK-LABEL: mismatched_prototypes:
119 ; SLOW: return_call baz, $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
120 ; FAST: i32.call $push[[L:[0-9]+]]=, baz, $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
121 ; FAST: return $pop[[L]]{{$}}
122 declare i32 @baz(i32, i32, i32)
123 define i32 @mismatched_prototypes() {
124 %v = tail call i32 @baz(i32 0, i32 42, i32 6)
128 ; CHECK-LABEL: mismatched_return_void:
129 ; CHECK: i32.call $drop=, baz, $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
131 define void @mismatched_return_void() {
132 %v = tail call i32 @baz(i32 0, i32 42, i32 6)
136 ; CHECK-LABEL: mismatched_return_f32:
137 ; CHECK: i32.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]]{{$}}
140 define float @mismatched_return_f32() {
141 %v = tail call i32 @baz(i32 0, i32 42, i32 6)
142 %u = bitcast i32 %v to float
146 ; CHECK-LABEL: mismatched_indirect_void:
147 ; CHECK: i32.call_indirect $drop=, $0, $1, $2, $0{{$}}
149 define 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)
155 ; CHECK-LABEL: mismatched_indirect_f32:
156 ; CHECK: i32.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]]{{$}}
159 define 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
166 ; CHECK-LABEL: mismatched_byval:
168 ; CHECK: return_call quux, $pop{{[0-9]+}}{{$}}
169 declare i32 @quux(i32* byval)
170 define i32 @mismatched_byval(i32* %x) {
171 %v = tail call i32 @quux(i32* byval %x)
175 ; CHECK-LABEL: varargs:
177 ; CHECK: i32.call $0=, var, $1{{$}}
178 ; CHECK: return $0{{$}}
179 declare i32 @var(...)
180 define i32 @varargs(i32 %x) {
181 %v = tail call i32 (...) @var(i32 %x)
185 ; Type transformations inhibit tail calls, even when they are nops
187 ; CHECK-LABEL: mismatched_return_zext:
189 define i32 @mismatched_return_zext() {
190 %v = tail call i1 @foo(i1 1)
191 %u = zext i1 %v to i32
195 ; CHECK-LABEL: mismatched_return_sext:
197 define i32 @mismatched_return_sext() {
198 %v = tail call i1 @foo(i1 1)
199 %u = sext i1 %v to i32
203 ; CHECK-LABEL: mismatched_return_trunc:
206 define i1 @mismatched_return_trunc() {
207 %v = tail call i32 @int()
208 %u = trunc i32 %v to i1
214 ; Check that the signatures generated for external indirectly
215 ; return-called functions include the proper return types
217 ; YAML-LABEL: - Index: 8
218 ; YAML-NEXT: ReturnType: I32
219 ; YAML-NEXT: ParamTypes:
224 define i32 @unique_caller(i32 (i32, float, i64, double)** %p) {
225 %f = load i32 (i32, float, i64, double)*, i32 (i32, float, i64, double)** %p
226 %v = tail call i32 %f(i32 0, float 0., i64 0, double 0.)
230 ; CHECK-LABEL: .section .custom_section.target_features
231 ; CHECK-NEXT: .int8 1
232 ; CHECK-NEXT: .int8 43
233 ; CHECK-NEXT: .int8 9
234 ; CHECK-NEXT: .ascii "tail-call"