Thomas Lively | a1d97a9 | 2019-06-26 16:17:15 +0000 | [diff] [blame] | 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 |
Thomas Lively | e0a9dce | 2019-07-30 18:08:39 +0000 | [diff] [blame] | 3 | ; RUN: llc < %s --filetype=obj -mattr=+tail-call | obj2yaml | FileCheck --check-prefix=YAML %s |
Thomas Lively | eafe8ef | 2019-05-23 17:26:47 +0000 | [diff] [blame] | 4 | |
Thomas Lively | e0a9dce | 2019-07-30 18:08:39 +0000 | [diff] [blame] | 5 | ; Test that the tail calls lower correctly |
Thomas Lively | eafe8ef | 2019-05-23 17:26:47 +0000 | [diff] [blame] | 6 | |
| 7 | target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" |
| 8 | target triple = "wasm32-unknown-unknown" |
| 9 | |
Thomas Lively | a1d97a9 | 2019-06-26 16:17:15 +0000 | [diff] [blame] | 10 | %fn = type <{i32 (%fn, i32, i32)*}> |
| 11 | declare i1 @foo(i1) |
| 12 | declare i1 @bar(i1) |
| 13 | |
| 14 | ; CHECK-LABEL: recursive_notail_nullary: |
| 15 | ; CHECK: {{^}} call recursive_notail_nullary{{$}} |
| 16 | ; CHECK-NEXT: return |
| 17 | define 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{{$}} |
| 24 | define 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{{$}} |
| 33 | define 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]]{{$}} |
| 41 | define 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{{$}} |
| 48 | define i32 @recursive_musttail(i32 %x, i32 %y) { |
| 49 | %v = musttail call i32 @recursive_musttail(i32 %x, i32 %y) |
| 50 | ret i32 %v |
| 51 | } |
| 52 | |
Thomas Lively | eafe8ef | 2019-05-23 17:26:47 +0000 | [diff] [blame] | 53 | ; CHECK-LABEL: recursive_tail: |
Thomas Lively | a1d97a9 | 2019-06-26 16:17:15 +0000 | [diff] [blame] | 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) |
| 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]]{{$}} |
| 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) |
| 68 | ret i32 %v |
| 69 | } |
| 70 | |
| 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) |
| 76 | ret i32 %v |
| 77 | } |
| 78 | |
| 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) |
| 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]]{{$}} |
| 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) |
| 93 | ret i1 %v |
| 94 | } |
| 95 | |
| 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) |
| 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]]{{$}} |
| 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) |
| 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]]{{$}} |
| 122 | declare i32 @baz(i32, i32, i32) |
| 123 | define i32 @mismatched_prototypes() { |
| 124 | %v = tail call i32 @baz(i32 0, i32 42, i32 6) |
| 125 | ret i32 %v |
| 126 | } |
| 127 | |
Thomas Lively | e0a9dce | 2019-07-30 18:08:39 +0000 | [diff] [blame] | 128 | ; CHECK-LABEL: mismatched_return_void: |
| 129 | ; CHECK: i32.call $drop=, baz, $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}} |
| 130 | ; CHECK: return{{$}} |
| 131 | define 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]]{{$}} |
| 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 |
| 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{{$}} |
| 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) |
| 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]]{{$}} |
| 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 |
| 163 | ret float %u |
| 164 | } |
| 165 | |
Thomas Lively | a1d97a9 | 2019-06-26 16:17:15 +0000 | [diff] [blame] | 166 | ; CHECK-LABEL: mismatched_byval: |
| 167 | ; CHECK: i32.store |
| 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) |
| 172 | ret i32 %v |
| 173 | } |
| 174 | |
| 175 | ; CHECK-LABEL: varargs: |
| 176 | ; CHECK: i32.store |
Thomas Lively | e0a9dce | 2019-07-30 18:08:39 +0000 | [diff] [blame] | 177 | ; CHECK: i32.call $0=, var, $1{{$}} |
| 178 | ; CHECK: return $0{{$}} |
Thomas Lively | a1d97a9 | 2019-06-26 16:17:15 +0000 | [diff] [blame] | 179 | declare i32 @var(...) |
| 180 | define i32 @varargs(i32 %x) { |
| 181 | %v = tail call i32 (...) @var(i32 %x) |
Thomas Lively | eafe8ef | 2019-05-23 17:26:47 +0000 | [diff] [blame] | 182 | ret i32 %v |
| 183 | } |
| 184 | |
Thomas Lively | e0a9dce | 2019-07-30 18:08:39 +0000 | [diff] [blame] | 185 | ; Type transformations inhibit tail calls, even when they are nops |
| 186 | |
| 187 | ; CHECK-LABEL: mismatched_return_zext: |
| 188 | ; CHECK: i32.call |
| 189 | define 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 |
| 197 | define 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 |
| 205 | declare i32 @int() |
| 206 | define 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 |
| 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.) |
| 227 | ret i32 %v |
| 228 | } |
| 229 | |
Thomas Lively | eafe8ef | 2019-05-23 17:26:47 +0000 | [diff] [blame] | 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" |