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