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: i32.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: i32.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: i32.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: i32.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: i32.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: i32.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: i32.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: 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]]{{$}} 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: i32.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: 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]]{{$}} 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) 170define i32 @mismatched_byval(i32* %x) { 171 %v = tail call i32 @quux(i32* byval %x) 172 ret i32 %v 173} 174 175; CHECK-LABEL: varargs: 176; CHECK: i32.store 177; CHECK: i32.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: i32.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: i32.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: i32.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 213 214; Check that the signatures generated for external indirectly 215; return-called functions include the proper return types 216 217; YAML-LABEL: - Index: 8 218; YAML-NEXT: ReturnType: I32 219; YAML-NEXT: ParamTypes: 220; YAML-NEXT: - I32 221; YAML-NEXT: - F32 222; YAML-NEXT: - I64 223; YAML-NEXT: - F64 224define 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.) 227 ret i32 %v 228} 229 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" 235