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