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