1; RUN: llc < %s -asm-verbose=false -verify-machineinstrs -mcpu=mvp -mattr=+multivalue,+tail-call -target-abi=experimental-mv | FileCheck %s 2; RUN: llc < %s -asm-verbose=false -verify-machineinstrs -mcpu=mvp -mattr=+reference-types,+multivalue,+tail-call -target-abi=experimental-mv | FileCheck --check-prefix REF %s 3; RUN: llc < %s -asm-verbose=false -verify-machineinstrs -disable-wasm-fallthrough-return-opt -wasm-disable-explicit-locals -wasm-keep-registers -mcpu=mvp -mattr=+multivalue,+tail-call -target-abi=experimental-mv | FileCheck %s --check-prefix REGS 4; RUN: llc < %s --filetype=obj -mcpu=mvp -mattr=+multivalue,+tail-call -target-abi=experimental-mv | obj2yaml | FileCheck %s --check-prefix OBJ 5; RUN: llc < %s -asm-verbose=false -verify-machineinstrs -mcpu=mvp -mattr=+multivalue,+tail-call | FileCheck %s --check-prefix NO-MULTIVALUE 6 7; Test that the multivalue calls, returns, function types, and block 8; types work as expected. 9 10target triple = "wasm32-unknown-unknown" 11 12%pair = type { i32, i64 } 13%rpair = type { i64, i32 } 14 15declare void @use_i32(i32) 16declare void @use_i64(i64) 17 18; CHECK-LABEL: pair_const: 19; CHECK-NEXT: .functype pair_const () -> (i32, i64) 20; CHECK-NEXT: i32.const 42{{$}} 21; CHECK-NEXT: i64.const 42{{$}} 22; CHECK-NEXT: end_function{{$}} 23; NO-MULTIVALUE-NOT: .functype pair_const () -> (i32, i64) 24define %pair @pair_const() { 25 ret %pair { i32 42, i64 42 } 26} 27 28; CHECK-LABEL: pair_ident: 29; CHECK-NEXT: .functype pair_ident (i32, i64) -> (i32, i64) 30; CHECK-NEXT: local.get 0{{$}} 31; CHECK-NEXT: local.get 1{{$}} 32; CHECK-NEXT: end_function{{$}} 33define %pair @pair_ident(%pair %p) { 34 ret %pair %p 35} 36 37; CHECK-LABEL: pair_call: 38; CHECK-NEXT: .functype pair_call () -> () 39; CHECK-NEXT: call pair_const{{$}} 40; CHECK-NEXT: drop{{$}} 41; CHECK-NEXT: drop{{$}} 42; CHECK-NEXT: end_function{{$}} 43; REGS: call $drop=, $drop=, pair_const{{$}} 44define void @pair_call() { 45 %p = call %pair @pair_const() 46 ret void 47} 48 49; CHECK-LABEL: pair_call_return: 50; CHECK-NEXT: .functype pair_call_return () -> (i32, i64) 51; CHECK-NEXT: call pair_const{{$}} 52; CHECK-NEXT: end_function{{$}} 53; REGS: call $push{{[0-9]+}}=, $push{{[0-9]+}}=, pair_const{{$}} 54define %pair @pair_call_return() { 55 %p = call %pair @pair_const() 56 ret %pair %p 57} 58 59; CHECK-LABEL: pair_call_indirect: 60; CHECK-NEXT: .functype pair_call_indirect (i32) -> (i32, i64) 61; CHECK-NEXT: local.get 0{{$}} 62; CHECK-NEXT: call_indirect () -> (i32, i64){{$}} 63; REF: call_indirect __indirect_function_table, () -> (i32, i64){{$}} 64; CHECK-NEXT: end_function{{$}} 65; REGS: call_indirect $push{{[0-9]+}}=, $push{{[0-9]+}}=, $0{{$}} 66define %pair @pair_call_indirect(ptr %f) { 67 %p = call %pair %f() 68 ret %pair %p 69} 70 71; CHECK-LABEL: pair_tail_call: 72; CHECK-NEXT: .functype pair_tail_call () -> (i32, i64) 73; CHECK-NEXT: return_call pair_const{{$}} 74; CHECK-NEXT: end_function{{$}} 75; REGS: return_call pair_const{{$}} 76define %pair @pair_tail_call() { 77 %p = musttail call %pair @pair_const() 78 ret %pair %p 79} 80 81; CHECK-LABEL: pair_call_return_first: 82; CHECK-NEXT: .functype pair_call_return_first () -> (i32) 83; CHECK-NEXT: call pair_const{{$}} 84; CHECK-NEXT: drop{{$}} 85; CHECK-NEXT: end_function{{$}} 86; REGS: call $push{{[0-9]+}}=, $drop=, pair_const{{$}} 87define i32 @pair_call_return_first() { 88 %p = call %pair @pair_const() 89 %v = extractvalue %pair %p, 0 90 ret i32 %v 91} 92 93; CHECK-LABEL: pair_call_return_second: 94; CHECK-NEXT: .functype pair_call_return_second () -> (i64) 95; CHECK-NEXT: .local i64{{$}} 96; CHECK-NEXT: call pair_const{{$}} 97; CHECK-NEXT: local.set 0{{$}} 98; CHECK-NEXT: drop{{$}} 99; CHECK-NEXT: local.get 0{{$}} 100; CHECK-NEXT: end_function{{$}} 101; REGS: call $drop=, $0=, pair_const{{$}} 102define i64 @pair_call_return_second() { 103 %p = call %pair @pair_const() 104 %v = extractvalue %pair %p, 1 105 ret i64 %v 106} 107 108; CHECK-LABEL: pair_call_use_first: 109; CHECK-NEXT: .functype pair_call_use_first () -> () 110; CHECK-NEXT: call pair_const{{$}} 111; CHECK-NEXT: drop{{$}} 112; CHECK-NEXT: call use_i32{{$}} 113; CHECK-NEXT: end_function{{$}} 114; REGS: call $push{{[0-9]+}}=, $drop=, pair_const{{$}} 115define void @pair_call_use_first() { 116 %p = call %pair @pair_const() 117 %v = extractvalue %pair %p, 0 118 call void @use_i32(i32 %v) 119 ret void 120} 121 122; CHECK-LABEL: pair_call_use_second: 123; CHECK-NEXT: .functype pair_call_use_second () -> () 124; CHECK-NEXT: .local i64 125; CHECK-NEXT: call pair_const{{$}} 126; CHECK-NEXT: local.set 0{{$}} 127; CHECK-NEXT: drop{{$}} 128; CHECK-NEXT: local.get 0{{$}} 129; CHECK-NEXT: call use_i64{{$}} 130; CHECK-NEXT: end_function{{$}} 131; REGS: call $drop=, $0=, pair_const{{$}} 132define void @pair_call_use_second() { 133 %p = call %pair @pair_const() 134 %v = extractvalue %pair %p, 1 135 call void @use_i64(i64 %v) 136 ret void 137} 138 139; CHECK-LABEL: pair_call_use_first_return_second: 140; CHECK-NEXT: .functype pair_call_use_first_return_second () -> (i64) 141; CHECK-NEXT: .local i64{{$}} 142; CHECK-NEXT: call pair_const{{$}} 143; CHECK-NEXT: local.set 0{{$}} 144; CHECK-NEXT: call use_i32{{$}} 145; CHECK-NEXT: local.get 0{{$}} 146; CHECK-NEXT: end_function{{$}} 147; REGS: call $push{{[0-9]+}}=, $0=, pair_const{{$}} 148define i64 @pair_call_use_first_return_second() { 149 %p = call %pair @pair_const() 150 %v = extractvalue %pair %p, 0 151 call void @use_i32(i32 %v) 152 %r = extractvalue %pair %p, 1 153 ret i64 %r 154} 155 156; CHECK-LABEL: pair_call_use_second_return_first: 157; CHECK-NEXT: .functype pair_call_use_second_return_first () -> (i32) 158; CHECK-NEXT: .local i32, i64{{$}} 159; CHECK-NEXT: call pair_const{{$}} 160; CHECK-NEXT: local.set 1{{$}} 161; CHECK-NEXT: local.set 0{{$}} 162; CHECK-NEXT: local.get 1{{$}} 163; CHECK-NEXT: call use_i64{{$}} 164; CHECK-NEXT: local.get 0{{$}} 165; CHECK-NEXT: end_function{{$}} 166; REGS: call $0=, $1=, pair_const{{$}} 167define i32 @pair_call_use_second_return_first() { 168 %p = call %pair @pair_const() 169 %v = extractvalue %pair %p, 1 170 call void @use_i64(i64 %v) 171 %r = extractvalue %pair %p, 0 172 ret i32 %r 173} 174 175; CHECK-LABEL: pair_pass_through: 176; CHECK-NEXT: .functype pair_pass_through (i32, i64) -> (i32, i64) 177; CHECK-NEXT: local.get 0 178; CHECK-NEXT: local.get 1 179; CHECK-NEXT: call pair_ident{{$}} 180; CHECK-NEXT: end_function{{$}} 181; REGS: call $push{{[0-9]+}}=, $push{{[0-9]+}}=, pair_ident, $0, $1{{$}} 182define %pair @pair_pass_through(%pair %p) { 183 %r = call %pair @pair_ident(%pair %p) 184 ret %pair %r 185} 186 187; CHECK-LABEL: pair_swap: 188; CHECK-NEXT: .functype pair_swap (i32, i64) -> (i64, i32) 189; CHECK-NEXT: local.get 1{{$}} 190; CHECK-NEXT: local.get 0{{$}} 191; CHECK-NEXT: end_function{{$}} 192define %rpair @pair_swap(%pair %p) { 193 %first = extractvalue %pair %p, 0 194 %second = extractvalue %pair %p, 1 195 %r1 = insertvalue %rpair undef, i32 %first, 1 196 %r2 = insertvalue %rpair %r1, i64 %second, 0 197 ret %rpair %r2 198} 199 200; CHECK-LABEL: pair_call_swap: 201; CHECK-NEXT: .functype pair_call_swap () -> (i64, i32) 202; CHECK-NEXT: .local i32, i64{{$}} 203; CHECK-NEXT: call pair_const{{$}} 204; CHECK-NEXT: local.set 1{{$}} 205; CHECK-NEXT: local.set 0{{$}} 206; CHECK-NEXT: local.get 1{{$}} 207; CHECK-NEXT: local.get 0{{$}} 208; CHECK-NEXT: end_function{{$}} 209; REGS: call $0=, $1=, pair_const{{$}} 210define %rpair @pair_call_swap() { 211 %p = call %pair @pair_const() 212 %first = extractvalue %pair %p, 0 213 %second = extractvalue %pair %p, 1 214 %r1 = insertvalue %rpair undef, i32 %first, 1 215 %r2 = insertvalue %rpair %r1, i64 %second, 0 216 ret %rpair %r2 217} 218 219; CHECK-LABEL: pair_pass_through_swap: 220; CHECK-NEXT: .functype pair_pass_through_swap (i32, i64) -> (i64, i32) 221; CHECK-NEXT: local.get 0{{$}} 222; CHECK-NEXT: local.get 1{{$}} 223; CHECK-NEXT: call pair_ident{{$}} 224; CHECK-NEXT: local.set 1{{$}} 225; CHECK-NEXT: local.set 0{{$}} 226; CHECK-NEXT: local.get 1{{$}} 227; CHECK-NEXT: local.get 0{{$}} 228; CHECK-NEXT: end_function{{$}} 229; REGS: call $0=, $1=, pair_ident, $0, $1{{$}} 230define %rpair @pair_pass_through_swap(%pair %p) { 231 %p1 = call %pair @pair_ident(%pair %p) 232 %first = extractvalue %pair %p1, 0 233 %second = extractvalue %pair %p1, 1 234 %r1 = insertvalue %rpair undef, i32 %first, 1 235 %r2 = insertvalue %rpair %r1, i64 %second, 0 236 ret %rpair %r2 237} 238 239; CHECK-LABEL: minimal_loop: 240; CHECK-NEXT: .functype minimal_loop (i32) -> (i32, i64) 241; CHECK-NEXT: .LBB{{[0-9]+}}_1: 242; CHECK-NEXT: loop () -> (i32, i64) 243; CHECK-NEXT: br 0{{$}} 244; CHECK-NEXT: .LBB{{[0-9]+}}_2: 245; CHECK-NEXT: end_loop{{$}} 246; CHECK-NEXT: end_function{{$}} 247define %pair @minimal_loop(ptr %p) { 248entry: 249 br label %loop 250loop: 251 br label %loop 252} 253 254; CHECK-LABEL: .section .custom_section.target_features 255; CHECK-NEXT: .int8 2 256; CHECK-NEXT: .int8 43 257; CHECK-NEXT: .int8 10 258; CHECK-NEXT: .ascii "multivalue" 259; CHECK-NEXT: .int8 43 260; CHECK-NEXT: .int8 9 261; CHECK-NEXT: .ascii "tail-call" 262 263; OBJ-LABEL: - Type: TYPE 264; OBJ-NEXT: Signatures: 265; OBJ-NEXT: - Index: 0 266; OBJ-NEXT: ParamTypes: [] 267; OBJ-NEXT: ReturnTypes: 268; OBJ-NEXT: - I32 269; OBJ-NEXT: - I64 270; OBJ-NEXT: - Index: 1 271; OBJ-NEXT: ParamTypes: 272; OBJ-NEXT: - I32 273; OBJ-NEXT: - I64 274; OBJ-NEXT: ReturnTypes: 275; OBJ-NEXT: - I32 276; OBJ-NEXT: - I64 277; OBJ-NEXT: - Index: 2 278; OBJ-NEXT: ParamTypes: [] 279; OBJ-NEXT: ReturnTypes: [] 280; OBJ-NEXT: - Index: 3 281; OBJ-NEXT: ParamTypes: 282; OBJ-NEXT: - I32 283; OBJ-NEXT: ReturnTypes: 284; OBJ-NEXT: - I32 285; OBJ-NEXT: - I64 286; OBJ-NEXT: - Index: 4 287; OBJ-NEXT: ParamTypes: [] 288; OBJ-NEXT: ReturnTypes: 289; OBJ-NEXT: - I32 290; OBJ-NEXT: - Index: 5 291; OBJ-NEXT: ParamTypes: [] 292; OBJ-NEXT: ReturnTypes: 293; OBJ-NEXT: - I64 294; OBJ-NEXT: - Index: 6 295; OBJ-NEXT: ParamTypes: 296; OBJ-NEXT: - I32 297; OBJ-NEXT: ReturnTypes: [] 298; OBJ-NEXT: - Index: 7 299; OBJ-NEXT: ParamTypes: 300; OBJ-NEXT: - I64 301; OBJ-NEXT: ReturnTypes: [] 302; OBJ-NEXT: - Index: 8 303; OBJ-NEXT: ParamTypes: 304; OBJ-NEXT: - I32 305; OBJ-NEXT: - I64 306; OBJ-NEXT: ReturnTypes: 307; OBJ-NEXT: - I64 308; OBJ-NEXT: - I32 309; OBJ-NEXT: - Index: 9 310; OBJ-NEXT: ParamTypes: [] 311; OBJ-NEXT: ReturnTypes: 312; OBJ-NEXT: - I64 313; OBJ-NEXT: - I32 314