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