xref: /llvm-project/llvm/test/CodeGen/WebAssembly/multivalue.ll (revision c921ac724ff06997bab25715786c98d4926b0c0e)
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