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