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