1; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers -mattr=+sign-ext,+simd128 | FileCheck --check-prefixes=CHECK,NO-TAIL %s 2; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers -fast-isel -fast-isel-abort=1 -mattr=+sign-ext,+simd128 | FileCheck --check-prefixes=CHECK,NO-TAIL %s 3; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers -mattr=+sign-ext,+simd128,+tail-call | FileCheck --check-prefixes=CHECK,SLOW-TAIL %s 4; RUN: llc < %s -asm-verbose=false -disable-wasm-fallthrough-return-opt -wasm-keep-registers -fast-isel -fast-isel-abort=1 -mattr=+sign-ext,+simd128,+tail-call | FileCheck --check-prefixes=CHECK,FAST-TAIL %s 5 6; Test that basic call operations assemble as expected. 7 8target triple = "wasm32-unknown-unknown" 9 10declare i32 @i32_nullary() 11declare i32 @i32_unary(i32) 12declare i32 @i32_binary(i32, i32) 13declare i64 @i64_nullary() 14declare float @float_nullary() 15declare double @double_nullary() 16declare <16 x i8> @v128_nullary() 17declare void @void_nullary() 18 19; CHECK-LABEL: call_i32_nullary: 20; CHECK-NEXT: .functype call_i32_nullary () -> (i32){{$}} 21; CHECK-NEXT: {{^}} call $push[[NUM:[0-9]+]]=, i32_nullary{{$}} 22; CHECK-NEXT: return $pop[[NUM]]{{$}} 23define i32 @call_i32_nullary() { 24 %r = call i32 @i32_nullary() 25 ret i32 %r 26} 27 28; CHECK-LABEL: call_i64_nullary: 29; CHECK-NEXT: .functype call_i64_nullary () -> (i64){{$}} 30; CHECK-NEXT: {{^}} call $push[[NUM:[0-9]+]]=, i64_nullary{{$}} 31; CHECK-NEXT: return $pop[[NUM]]{{$}} 32define i64 @call_i64_nullary() { 33 %r = call i64 @i64_nullary() 34 ret i64 %r 35} 36 37; CHECK-LABEL: call_float_nullary: 38; CHECK-NEXT: .functype call_float_nullary () -> (f32){{$}} 39; CHECK-NEXT: {{^}} call $push[[NUM:[0-9]+]]=, float_nullary{{$}} 40; CHECK-NEXT: return $pop[[NUM]]{{$}} 41define float @call_float_nullary() { 42 %r = call float @float_nullary() 43 ret float %r 44} 45 46; CHECK-LABEL: call_double_nullary: 47; CHECK-NEXT: .functype call_double_nullary () -> (f64){{$}} 48; CHECK-NEXT: {{^}} call $push[[NUM:[0-9]+]]=, double_nullary{{$}} 49; CHECK-NEXT: return $pop[[NUM]]{{$}} 50define double @call_double_nullary() { 51 %r = call double @double_nullary() 52 ret double %r 53} 54 55; CHECK-LABEL: call_v128_nullary: 56; CHECK-NEXT: .functype call_v128_nullary () -> (v128){{$}} 57; CHECK-NEXT: {{^}} call $push[[NUM:[0-9]+]]=, v128_nullary{{$}} 58; CHECK-NEXT: return $pop[[NUM]]{{$}} 59define <16 x i8> @call_v128_nullary() { 60 %r = call <16 x i8> @v128_nullary() 61 ret <16 x i8> %r 62} 63 64; CHECK-LABEL: call_void_nullary: 65; CHECK-NEXT: .functype call_void_nullary () -> (){{$}} 66; CHECK-NEXT: {{^}} call void_nullary{{$}} 67; CHECK-NEXT: return{{$}} 68define void @call_void_nullary() { 69 call void @void_nullary() 70 ret void 71} 72 73; CHECK-LABEL: call_i32_unary: 74; CHECK-NEXT: .functype call_i32_unary (i32) -> (i32){{$}} 75; CHECK-NEXT: local.get $push[[L0:[0-9]+]]=, 0{{$}} 76; CHECK-NEXT: {{^}} call $push[[NUM:[0-9]+]]=, i32_unary, $pop[[L0]]{{$}} 77; CHECK-NEXT: return $pop[[NUM]]{{$}} 78define i32 @call_i32_unary(i32 %a) { 79 %r = call i32 @i32_unary(i32 %a) 80 ret i32 %r 81} 82 83; CHECK-LABEL: call_i32_binary: 84; CHECK-NEXT: .functype call_i32_binary (i32, i32) -> (i32){{$}} 85; CHECK-NEXT: local.get $push[[L0:[0-9]+]]=, 0{{$}} 86; CHECK-NEXT: local.get $push[[L1:[0-9]+]]=, 1{{$}} 87; CHECK-NEXT: {{^}} call $push[[NUM:[0-9]+]]=, i32_binary, $pop[[L0]], $pop[[L1]]{{$}} 88; CHECK-NEXT: return $pop[[NUM]]{{$}} 89define i32 @call_i32_binary(i32 %a, i32 %b) { 90 %r = call i32 @i32_binary(i32 %a, i32 %b) 91 ret i32 %r 92} 93 94; CHECK-LABEL: call_indirect_void: 95; CHECK-NEXT: .functype call_indirect_void (i32) -> (){{$}} 96; CHECK-NEXT: local.get $push[[L0:[0-9]+]]=, 0{{$}} 97; CHECK-NEXT: {{^}} call_indirect $pop[[L0]]{{$}} 98; CHECK-NEXT: return{{$}} 99define void @call_indirect_void(void ()* %callee) { 100 call void %callee() 101 ret void 102} 103 104; CHECK-LABEL: call_indirect_i32: 105; CHECK-NEXT: .functype call_indirect_i32 (i32) -> (i32){{$}} 106; CHECK-NEXT: local.get $push[[L0:[0-9]+]]=, 0{{$}} 107; CHECK-NEXT: {{^}} call_indirect $push[[NUM:[0-9]+]]=, $pop[[L0]]{{$}} 108; CHECK-NEXT: return $pop[[NUM]]{{$}} 109define i32 @call_indirect_i32(i32 ()* %callee) { 110 %t = call i32 %callee() 111 ret i32 %t 112} 113 114; CHECK-LABEL: call_indirect_i64: 115; CHECK-NEXT: .functype call_indirect_i64 (i32) -> (i64){{$}} 116; CHECK-NEXT: local.get $push[[L0:[0-9]+]]=, 0{{$}} 117; CHECK-NEXT: {{^}} call_indirect $push[[NUM:[0-9]+]]=, $pop[[L0]]{{$}} 118; CHECK-NEXT: return $pop[[NUM]]{{$}} 119define i64 @call_indirect_i64(i64 ()* %callee) { 120 %t = call i64 %callee() 121 ret i64 %t 122} 123 124; CHECK-LABEL: call_indirect_float: 125; CHECK-NEXT: .functype call_indirect_float (i32) -> (f32){{$}} 126; CHECK-NEXT: local.get $push[[L0:[0-9]+]]=, 0{{$}} 127; CHECK-NEXT: {{^}} call_indirect $push[[NUM:[0-9]+]]=, $pop[[L0]]{{$}} 128; CHECK-NEXT: return $pop[[NUM]]{{$}} 129define float @call_indirect_float(float ()* %callee) { 130 %t = call float %callee() 131 ret float %t 132} 133 134; CHECK-LABEL: call_indirect_double: 135; CHECK-NEXT: .functype call_indirect_double (i32) -> (f64){{$}} 136; CHECK-NEXT: local.get $push[[L0:[0-9]+]]=, 0{{$}} 137; CHECK-NEXT: {{^}} call_indirect $push[[NUM:[0-9]+]]=, $pop[[L0]]{{$}} 138; CHECK-NEXT: return $pop[[NUM]]{{$}} 139define double @call_indirect_double(double ()* %callee) { 140 %t = call double %callee() 141 ret double %t 142} 143 144; CHECK-LABEL: call_indirect_v128: 145; CHECK-NEXT: .functype call_indirect_v128 (i32) -> (v128){{$}} 146; CHECK-NEXT: local.get $push[[L0:[0-9]+]]=, 0{{$}} 147; CHECK-NEXT: {{^}} call_indirect $push[[NUM:[0-9]+]]=, $pop[[L0]]{{$}} 148; CHECK-NEXT: return $pop[[NUM]]{{$}} 149define <16 x i8> @call_indirect_v128(<16 x i8> ()* %callee) { 150 %t = call <16 x i8> %callee() 151 ret <16 x i8> %t 152} 153 154; CHECK-LABEL: call_indirect_arg: 155; CHECK-NEXT: .functype call_indirect_arg (i32, i32) -> (){{$}} 156; CHECK-NEXT: local.get $push[[L0:[0-9]+]]=, 1{{$}} 157; CHECK-NEXT: local.get $push[[L1:[0-9]+]]=, 0{{$}} 158; CHECK-NEXT: {{^}} call_indirect $pop[[L0]], $pop[[L1]]{{$}} 159; CHECK-NEXT: return{{$}} 160define void @call_indirect_arg(void (i32)* %callee, i32 %arg) { 161 call void %callee(i32 %arg) 162 ret void 163} 164 165; CHECK-LABEL: call_indirect_arg_2: 166; CHECK-NEXT: .functype call_indirect_arg_2 (i32, i32, i32) -> (){{$}} 167; CHECK-NEXT: local.get $push[[L0:[0-9]+]]=, 1{{$}} 168; CHECK-NEXT: local.get $push[[L1:[0-9]+]]=, 2{{$}} 169; CHECK-NEXT: local.get $push[[L2:[0-9]+]]=, 0{{$}} 170; CHECK-NEXT: {{^}} call_indirect $push[[NUM:[0-9]+]]=, $pop[[L0]], $pop[[L1]], $pop[[L2]]{{$}} 171; CHECK-NEXT: drop $pop[[NUM]]{{$}} 172; CHECK-NEXT: return{{$}} 173define void @call_indirect_arg_2(i32 (i32, i32)* %callee, i32 %arg, i32 %arg2) { 174 call i32 %callee(i32 %arg, i32 %arg2) 175 ret void 176} 177 178; CHECK-LABEL: tail_call_void_nullary: 179; CHECK-NEXT: .functype tail_call_void_nullary () -> (){{$}} 180; NO-TAIL-NEXT: {{^}} call void_nullary{{$}} 181; NO-TAIL-NEXT: return{{$}} 182; SLOW-TAIL-NEXT: {{^}} return_call void_nullary{{$}} 183; FAST-TAIL-NEXT: {{^}} call void_nullary{{$}} 184; FAST-TAIL-NEXT: return{{$}} 185define void @tail_call_void_nullary() { 186 tail call void @void_nullary() 187 ret void 188} 189 190; CHECK-LABEL: fastcc_tail_call_void_nullary: 191; CHECK-NEXT: .functype fastcc_tail_call_void_nullary () -> (){{$}} 192; NO-TAIL-NEXT: {{^}} call void_nullary{{$}} 193; NO-TAIL-NEXT: return{{$}} 194; SLOW-TAIL-NEXT: {{^}} return_call void_nullary{{$}} 195; FAST-TAIL-NEXT: {{^}} call void_nullary{{$}} 196; FAST-TAIL-NEXT: return{{$}} 197define void @fastcc_tail_call_void_nullary() { 198 tail call fastcc void @void_nullary() 199 ret void 200} 201 202; CHECK-LABEL: coldcc_tail_call_void_nullary: 203; CHECK-NEXT: .functype coldcc_tail_call_void_nullary () -> (){{$}} 204; NO-TAIL-NEXT: {{^}} call void_nullary{{$}} 205; NO-TAIL-NEXT: return{{$}} 206; SLOW-TAIL-NEXT: {{^}} return_call void_nullary{{$}} 207; FAST-TAIL-NEXT: {{^}} call void_nullary{{$}} 208; FAST-TAIL-NEXT: return{{$}} 209define void @coldcc_tail_call_void_nullary() { 210 tail call coldcc void @void_nullary() 211 ret void 212} 213 214; CHECK-LABEL: call_constexpr: 215; CHECK-NEXT: .functype call_constexpr () -> (){{$}} 216; CHECK-NEXT: i32.const $push[[L0:[0-9]+]]=, 2{{$}} 217; CHECK-NEXT: i32.const $push[[L1:[0-9]+]]=, 3{{$}} 218; CHECK-NEXT: call .Lvararg_func_bitcast, $pop[[L0]], $pop[[L1]]{{$}} 219; CHECK-NEXT: call other_void_nullary{{$}} 220; CHECK-NEXT: call void_nullary{{$}} 221; CHECK-NEXT: return{{$}} 222declare void @vararg_func(...) 223declare void @other_void_nullary() 224define void @call_constexpr() { 225bb0: 226 call void bitcast (void (...)* @vararg_func to void (i32, i32)*)(i32 2, i32 3) 227 br label %bb1 228bb1: 229 call void select (i1 0, void ()* @void_nullary, void ()* @other_void_nullary)() 230 br label %bb2 231bb2: 232 call void inttoptr (i32 ptrtoint (void ()* @void_nullary to i32) to void ()*)() 233 ret void 234} 235 236; TODO: test the following: 237; - More argument combinations. 238; - Tail call. 239; - Interesting returns (struct, multiple). 240; - Vararg. 241