1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \
3; RUN:   | FileCheck -check-prefix=RV32I-FPELIM %s
4; RUN: llc -mtriple=riscv32 -mattr=+f -target-abi ilp32f \
5; RUN:    -verify-machineinstrs < %s \
6; RUN:   | FileCheck -check-prefix=RV32I-FPELIM %s
7; RUN: llc -mtriple=riscv32 -mattr=+d -target-abi ilp32d \
8; RUN:    -verify-machineinstrs < %s \
9; RUN:   | FileCheck -check-prefix=RV32I-FPELIM %s
10; RUN: llc -mtriple=riscv32 -verify-machineinstrs -frame-pointer=all < %s \
11; RUN:   | FileCheck -check-prefix=RV32I-WITHFP %s
12; RUN: llc -mtriple=riscv32 -verify-machineinstrs -frame-pointer=all \
13; RUN:   -mattr=+f -target-abi ilp32f < %s \
14; RUN:   | FileCheck -check-prefix=RV32I-WITHFP %s
15; RUN: llc -mtriple=riscv32 -verify-machineinstrs -frame-pointer=all \
16; RUN:   -mattr=+d -target-abi ilp32d < %s \
17; RUN:   | FileCheck -check-prefix=RV32I-WITHFP %s
18
19; This file contains tests that should have identical output for the ilp32,
20; ilp32f, and ilp32d ABIs. i.e. where no arguments are passed according to
21; the floating point ABI. As well as calling convention details, we check that
22; ra and fp are consistently stored to fp-4 and fp-8.
23
24; Check that on RV32, i64 is passed in a pair of registers. Unlike
25; the convention for varargs, this need not be an aligned pair.
26
27define i32 @callee_i64_in_regs(i32 %a, i64 %b) nounwind {
28; RV32I-FPELIM-LABEL: callee_i64_in_regs:
29; RV32I-FPELIM:       # %bb.0:
30; RV32I-FPELIM-NEXT:    add a0, a0, a1
31; RV32I-FPELIM-NEXT:    ret
32;
33; RV32I-WITHFP-LABEL: callee_i64_in_regs:
34; RV32I-WITHFP:       # %bb.0:
35; RV32I-WITHFP-NEXT:    addi sp, sp, -16
36; RV32I-WITHFP-NEXT:    sw ra, 12(sp)
37; RV32I-WITHFP-NEXT:    sw s0, 8(sp)
38; RV32I-WITHFP-NEXT:    addi s0, sp, 16
39; RV32I-WITHFP-NEXT:    add a0, a0, a1
40; RV32I-WITHFP-NEXT:    lw s0, 8(sp)
41; RV32I-WITHFP-NEXT:    lw ra, 12(sp)
42; RV32I-WITHFP-NEXT:    addi sp, sp, 16
43; RV32I-WITHFP-NEXT:    ret
44  %b_trunc = trunc i64 %b to i32
45  %1 = add i32 %a, %b_trunc
46  ret i32 %1
47}
48
49define i32 @caller_i64_in_regs() nounwind {
50; RV32I-FPELIM-LABEL: caller_i64_in_regs:
51; RV32I-FPELIM:       # %bb.0:
52; RV32I-FPELIM-NEXT:    addi sp, sp, -16
53; RV32I-FPELIM-NEXT:    sw ra, 12(sp)
54; RV32I-FPELIM-NEXT:    addi a0, zero, 1
55; RV32I-FPELIM-NEXT:    addi a1, zero, 2
56; RV32I-FPELIM-NEXT:    mv a2, zero
57; RV32I-FPELIM-NEXT:    call callee_i64_in_regs
58; RV32I-FPELIM-NEXT:    lw ra, 12(sp)
59; RV32I-FPELIM-NEXT:    addi sp, sp, 16
60; RV32I-FPELIM-NEXT:    ret
61;
62; RV32I-WITHFP-LABEL: caller_i64_in_regs:
63; RV32I-WITHFP:       # %bb.0:
64; RV32I-WITHFP-NEXT:    addi sp, sp, -16
65; RV32I-WITHFP-NEXT:    sw ra, 12(sp)
66; RV32I-WITHFP-NEXT:    sw s0, 8(sp)
67; RV32I-WITHFP-NEXT:    addi s0, sp, 16
68; RV32I-WITHFP-NEXT:    addi a0, zero, 1
69; RV32I-WITHFP-NEXT:    addi a1, zero, 2
70; RV32I-WITHFP-NEXT:    mv a2, zero
71; RV32I-WITHFP-NEXT:    call callee_i64_in_regs
72; RV32I-WITHFP-NEXT:    lw s0, 8(sp)
73; RV32I-WITHFP-NEXT:    lw ra, 12(sp)
74; RV32I-WITHFP-NEXT:    addi sp, sp, 16
75; RV32I-WITHFP-NEXT:    ret
76  %1 = call i32 @callee_i64_in_regs(i32 1, i64 2)
77  ret i32 %1
78}
79
80; Check that the stack is used once the GPRs are exhausted
81
82define i32 @callee_many_scalars(i8 %a, i16 %b, i32 %c, i64 %d, i32 %e, i32 %f, i64 %g, i32 %h) nounwind {
83; RV32I-FPELIM-LABEL: callee_many_scalars:
84; RV32I-FPELIM:       # %bb.0:
85; RV32I-FPELIM-NEXT:    lw t0, 4(sp)
86; RV32I-FPELIM-NEXT:    lw t1, 0(sp)
87; RV32I-FPELIM-NEXT:    andi t2, a0, 255
88; RV32I-FPELIM-NEXT:    lui a0, 16
89; RV32I-FPELIM-NEXT:    addi a0, a0, -1
90; RV32I-FPELIM-NEXT:    and a0, a1, a0
91; RV32I-FPELIM-NEXT:    add a0, t2, a0
92; RV32I-FPELIM-NEXT:    add a0, a0, a2
93; RV32I-FPELIM-NEXT:    xor a1, a4, t1
94; RV32I-FPELIM-NEXT:    xor a2, a3, a7
95; RV32I-FPELIM-NEXT:    or a1, a2, a1
96; RV32I-FPELIM-NEXT:    seqz a1, a1
97; RV32I-FPELIM-NEXT:    add a0, a1, a0
98; RV32I-FPELIM-NEXT:    add a0, a0, a5
99; RV32I-FPELIM-NEXT:    add a0, a0, a6
100; RV32I-FPELIM-NEXT:    add a0, a0, t0
101; RV32I-FPELIM-NEXT:    ret
102;
103; RV32I-WITHFP-LABEL: callee_many_scalars:
104; RV32I-WITHFP:       # %bb.0:
105; RV32I-WITHFP-NEXT:    addi sp, sp, -16
106; RV32I-WITHFP-NEXT:    sw ra, 12(sp)
107; RV32I-WITHFP-NEXT:    sw s0, 8(sp)
108; RV32I-WITHFP-NEXT:    addi s0, sp, 16
109; RV32I-WITHFP-NEXT:    lw t0, 4(s0)
110; RV32I-WITHFP-NEXT:    lw t1, 0(s0)
111; RV32I-WITHFP-NEXT:    andi t2, a0, 255
112; RV32I-WITHFP-NEXT:    lui a0, 16
113; RV32I-WITHFP-NEXT:    addi a0, a0, -1
114; RV32I-WITHFP-NEXT:    and a0, a1, a0
115; RV32I-WITHFP-NEXT:    add a0, t2, a0
116; RV32I-WITHFP-NEXT:    add a0, a0, a2
117; RV32I-WITHFP-NEXT:    xor a1, a4, t1
118; RV32I-WITHFP-NEXT:    xor a2, a3, a7
119; RV32I-WITHFP-NEXT:    or a1, a2, a1
120; RV32I-WITHFP-NEXT:    seqz a1, a1
121; RV32I-WITHFP-NEXT:    add a0, a1, a0
122; RV32I-WITHFP-NEXT:    add a0, a0, a5
123; RV32I-WITHFP-NEXT:    add a0, a0, a6
124; RV32I-WITHFP-NEXT:    add a0, a0, t0
125; RV32I-WITHFP-NEXT:    lw s0, 8(sp)
126; RV32I-WITHFP-NEXT:    lw ra, 12(sp)
127; RV32I-WITHFP-NEXT:    addi sp, sp, 16
128; RV32I-WITHFP-NEXT:    ret
129  %a_ext = zext i8 %a to i32
130  %b_ext = zext i16 %b to i32
131  %1 = add i32 %a_ext, %b_ext
132  %2 = add i32 %1, %c
133  %3 = icmp eq i64 %d, %g
134  %4 = zext i1 %3 to i32
135  %5 = add i32 %4, %2
136  %6 = add i32 %5, %e
137  %7 = add i32 %6, %f
138  %8 = add i32 %7, %h
139  ret i32 %8
140}
141
142define i32 @caller_many_scalars() nounwind {
143; RV32I-FPELIM-LABEL: caller_many_scalars:
144; RV32I-FPELIM:       # %bb.0:
145; RV32I-FPELIM-NEXT:    addi sp, sp, -16
146; RV32I-FPELIM-NEXT:    sw ra, 12(sp)
147; RV32I-FPELIM-NEXT:    addi a0, zero, 8
148; RV32I-FPELIM-NEXT:    sw a0, 4(sp)
149; RV32I-FPELIM-NEXT:    addi a0, zero, 1
150; RV32I-FPELIM-NEXT:    addi a1, zero, 2
151; RV32I-FPELIM-NEXT:    addi a2, zero, 3
152; RV32I-FPELIM-NEXT:    addi a3, zero, 4
153; RV32I-FPELIM-NEXT:    addi a5, zero, 5
154; RV32I-FPELIM-NEXT:    addi a6, zero, 6
155; RV32I-FPELIM-NEXT:    addi a7, zero, 7
156; RV32I-FPELIM-NEXT:    sw zero, 0(sp)
157; RV32I-FPELIM-NEXT:    mv a4, zero
158; RV32I-FPELIM-NEXT:    call callee_many_scalars
159; RV32I-FPELIM-NEXT:    lw ra, 12(sp)
160; RV32I-FPELIM-NEXT:    addi sp, sp, 16
161; RV32I-FPELIM-NEXT:    ret
162;
163; RV32I-WITHFP-LABEL: caller_many_scalars:
164; RV32I-WITHFP:       # %bb.0:
165; RV32I-WITHFP-NEXT:    addi sp, sp, -16
166; RV32I-WITHFP-NEXT:    sw ra, 12(sp)
167; RV32I-WITHFP-NEXT:    sw s0, 8(sp)
168; RV32I-WITHFP-NEXT:    addi s0, sp, 16
169; RV32I-WITHFP-NEXT:    addi a0, zero, 8
170; RV32I-WITHFP-NEXT:    sw a0, 4(sp)
171; RV32I-WITHFP-NEXT:    addi a0, zero, 1
172; RV32I-WITHFP-NEXT:    addi a1, zero, 2
173; RV32I-WITHFP-NEXT:    addi a2, zero, 3
174; RV32I-WITHFP-NEXT:    addi a3, zero, 4
175; RV32I-WITHFP-NEXT:    addi a5, zero, 5
176; RV32I-WITHFP-NEXT:    addi a6, zero, 6
177; RV32I-WITHFP-NEXT:    addi a7, zero, 7
178; RV32I-WITHFP-NEXT:    sw zero, 0(sp)
179; RV32I-WITHFP-NEXT:    mv a4, zero
180; RV32I-WITHFP-NEXT:    call callee_many_scalars
181; RV32I-WITHFP-NEXT:    lw s0, 8(sp)
182; RV32I-WITHFP-NEXT:    lw ra, 12(sp)
183; RV32I-WITHFP-NEXT:    addi sp, sp, 16
184; RV32I-WITHFP-NEXT:    ret
185  %1 = call i32 @callee_many_scalars(i8 1, i16 2, i32 3, i64 4, i32 5, i32 6, i64 7, i32 8)
186  ret i32 %1
187}
188
189
190; Check that i128 and fp128 are passed indirectly
191
192define i32 @callee_large_scalars(i128 %a, fp128 %b) nounwind {
193; RV32I-FPELIM-LABEL: callee_large_scalars:
194; RV32I-FPELIM:       # %bb.0:
195; RV32I-FPELIM-NEXT:    lw a6, 0(a1)
196; RV32I-FPELIM-NEXT:    lw a7, 0(a0)
197; RV32I-FPELIM-NEXT:    lw a4, 4(a1)
198; RV32I-FPELIM-NEXT:    lw a5, 12(a1)
199; RV32I-FPELIM-NEXT:    lw a2, 12(a0)
200; RV32I-FPELIM-NEXT:    lw a3, 4(a0)
201; RV32I-FPELIM-NEXT:    lw a1, 8(a1)
202; RV32I-FPELIM-NEXT:    lw a0, 8(a0)
203; RV32I-FPELIM-NEXT:    xor a2, a2, a5
204; RV32I-FPELIM-NEXT:    xor a3, a3, a4
205; RV32I-FPELIM-NEXT:    or a2, a3, a2
206; RV32I-FPELIM-NEXT:    xor a0, a0, a1
207; RV32I-FPELIM-NEXT:    xor a1, a7, a6
208; RV32I-FPELIM-NEXT:    or a0, a1, a0
209; RV32I-FPELIM-NEXT:    or a0, a0, a2
210; RV32I-FPELIM-NEXT:    seqz a0, a0
211; RV32I-FPELIM-NEXT:    ret
212;
213; RV32I-WITHFP-LABEL: callee_large_scalars:
214; RV32I-WITHFP:       # %bb.0:
215; RV32I-WITHFP-NEXT:    addi sp, sp, -16
216; RV32I-WITHFP-NEXT:    sw ra, 12(sp)
217; RV32I-WITHFP-NEXT:    sw s0, 8(sp)
218; RV32I-WITHFP-NEXT:    addi s0, sp, 16
219; RV32I-WITHFP-NEXT:    lw a6, 0(a1)
220; RV32I-WITHFP-NEXT:    lw a7, 0(a0)
221; RV32I-WITHFP-NEXT:    lw a4, 4(a1)
222; RV32I-WITHFP-NEXT:    lw a5, 12(a1)
223; RV32I-WITHFP-NEXT:    lw a2, 12(a0)
224; RV32I-WITHFP-NEXT:    lw a3, 4(a0)
225; RV32I-WITHFP-NEXT:    lw a1, 8(a1)
226; RV32I-WITHFP-NEXT:    lw a0, 8(a0)
227; RV32I-WITHFP-NEXT:    xor a2, a2, a5
228; RV32I-WITHFP-NEXT:    xor a3, a3, a4
229; RV32I-WITHFP-NEXT:    or a2, a3, a2
230; RV32I-WITHFP-NEXT:    xor a0, a0, a1
231; RV32I-WITHFP-NEXT:    xor a1, a7, a6
232; RV32I-WITHFP-NEXT:    or a0, a1, a0
233; RV32I-WITHFP-NEXT:    or a0, a0, a2
234; RV32I-WITHFP-NEXT:    seqz a0, a0
235; RV32I-WITHFP-NEXT:    lw s0, 8(sp)
236; RV32I-WITHFP-NEXT:    lw ra, 12(sp)
237; RV32I-WITHFP-NEXT:    addi sp, sp, 16
238; RV32I-WITHFP-NEXT:    ret
239  %b_bitcast = bitcast fp128 %b to i128
240  %1 = icmp eq i128 %a, %b_bitcast
241  %2 = zext i1 %1 to i32
242  ret i32 %2
243}
244
245define i32 @caller_large_scalars() nounwind {
246; RV32I-FPELIM-LABEL: caller_large_scalars:
247; RV32I-FPELIM:       # %bb.0:
248; RV32I-FPELIM-NEXT:    addi sp, sp, -48
249; RV32I-FPELIM-NEXT:    sw ra, 44(sp)
250; RV32I-FPELIM-NEXT:    lui a0, 524272
251; RV32I-FPELIM-NEXT:    sw a0, 12(sp)
252; RV32I-FPELIM-NEXT:    sw zero, 8(sp)
253; RV32I-FPELIM-NEXT:    sw zero, 4(sp)
254; RV32I-FPELIM-NEXT:    sw zero, 0(sp)
255; RV32I-FPELIM-NEXT:    sw zero, 36(sp)
256; RV32I-FPELIM-NEXT:    sw zero, 32(sp)
257; RV32I-FPELIM-NEXT:    sw zero, 28(sp)
258; RV32I-FPELIM-NEXT:    addi a2, zero, 1
259; RV32I-FPELIM-NEXT:    addi a0, sp, 24
260; RV32I-FPELIM-NEXT:    mv a1, sp
261; RV32I-FPELIM-NEXT:    sw a2, 24(sp)
262; RV32I-FPELIM-NEXT:    call callee_large_scalars
263; RV32I-FPELIM-NEXT:    lw ra, 44(sp)
264; RV32I-FPELIM-NEXT:    addi sp, sp, 48
265; RV32I-FPELIM-NEXT:    ret
266;
267; RV32I-WITHFP-LABEL: caller_large_scalars:
268; RV32I-WITHFP:       # %bb.0:
269; RV32I-WITHFP-NEXT:    addi sp, sp, -48
270; RV32I-WITHFP-NEXT:    sw ra, 44(sp)
271; RV32I-WITHFP-NEXT:    sw s0, 40(sp)
272; RV32I-WITHFP-NEXT:    addi s0, sp, 48
273; RV32I-WITHFP-NEXT:    lui a0, 524272
274; RV32I-WITHFP-NEXT:    sw a0, -36(s0)
275; RV32I-WITHFP-NEXT:    sw zero, -40(s0)
276; RV32I-WITHFP-NEXT:    sw zero, -44(s0)
277; RV32I-WITHFP-NEXT:    sw zero, -48(s0)
278; RV32I-WITHFP-NEXT:    sw zero, -12(s0)
279; RV32I-WITHFP-NEXT:    sw zero, -16(s0)
280; RV32I-WITHFP-NEXT:    sw zero, -20(s0)
281; RV32I-WITHFP-NEXT:    addi a2, zero, 1
282; RV32I-WITHFP-NEXT:    addi a0, s0, -24
283; RV32I-WITHFP-NEXT:    addi a1, s0, -48
284; RV32I-WITHFP-NEXT:    sw a2, -24(s0)
285; RV32I-WITHFP-NEXT:    call callee_large_scalars
286; RV32I-WITHFP-NEXT:    lw s0, 40(sp)
287; RV32I-WITHFP-NEXT:    lw ra, 44(sp)
288; RV32I-WITHFP-NEXT:    addi sp, sp, 48
289; RV32I-WITHFP-NEXT:    ret
290  %1 = call i32 @callee_large_scalars(i128 1, fp128 0xL00000000000000007FFF000000000000)
291  ret i32 %1
292}
293
294; Check that arguments larger than 2*xlen are handled correctly when their
295; address is passed on the stack rather than in memory
296
297; Must keep define on a single line due to an update_llc_test_checks.py limitation
298define i32 @callee_large_scalars_exhausted_regs(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, i128 %h, i32 %i, fp128 %j) nounwind {
299; RV32I-FPELIM-LABEL: callee_large_scalars_exhausted_regs:
300; RV32I-FPELIM:       # %bb.0:
301; RV32I-FPELIM-NEXT:    lw a0, 4(sp)
302; RV32I-FPELIM-NEXT:    lw a6, 0(a0)
303; RV32I-FPELIM-NEXT:    lw t0, 0(a7)
304; RV32I-FPELIM-NEXT:    lw a3, 4(a0)
305; RV32I-FPELIM-NEXT:    lw a4, 12(a0)
306; RV32I-FPELIM-NEXT:    lw a5, 12(a7)
307; RV32I-FPELIM-NEXT:    lw a1, 4(a7)
308; RV32I-FPELIM-NEXT:    lw a0, 8(a0)
309; RV32I-FPELIM-NEXT:    lw a2, 8(a7)
310; RV32I-FPELIM-NEXT:    xor a4, a5, a4
311; RV32I-FPELIM-NEXT:    xor a1, a1, a3
312; RV32I-FPELIM-NEXT:    or a1, a1, a4
313; RV32I-FPELIM-NEXT:    xor a0, a2, a0
314; RV32I-FPELIM-NEXT:    xor a2, t0, a6
315; RV32I-FPELIM-NEXT:    or a0, a2, a0
316; RV32I-FPELIM-NEXT:    or a0, a0, a1
317; RV32I-FPELIM-NEXT:    seqz a0, a0
318; RV32I-FPELIM-NEXT:    ret
319;
320; RV32I-WITHFP-LABEL: callee_large_scalars_exhausted_regs:
321; RV32I-WITHFP:       # %bb.0:
322; RV32I-WITHFP-NEXT:    addi sp, sp, -16
323; RV32I-WITHFP-NEXT:    sw ra, 12(sp)
324; RV32I-WITHFP-NEXT:    sw s0, 8(sp)
325; RV32I-WITHFP-NEXT:    addi s0, sp, 16
326; RV32I-WITHFP-NEXT:    lw a0, 4(s0)
327; RV32I-WITHFP-NEXT:    lw a6, 0(a0)
328; RV32I-WITHFP-NEXT:    lw t0, 0(a7)
329; RV32I-WITHFP-NEXT:    lw a3, 4(a0)
330; RV32I-WITHFP-NEXT:    lw a4, 12(a0)
331; RV32I-WITHFP-NEXT:    lw a5, 12(a7)
332; RV32I-WITHFP-NEXT:    lw a1, 4(a7)
333; RV32I-WITHFP-NEXT:    lw a0, 8(a0)
334; RV32I-WITHFP-NEXT:    lw a2, 8(a7)
335; RV32I-WITHFP-NEXT:    xor a4, a5, a4
336; RV32I-WITHFP-NEXT:    xor a1, a1, a3
337; RV32I-WITHFP-NEXT:    or a1, a1, a4
338; RV32I-WITHFP-NEXT:    xor a0, a2, a0
339; RV32I-WITHFP-NEXT:    xor a2, t0, a6
340; RV32I-WITHFP-NEXT:    or a0, a2, a0
341; RV32I-WITHFP-NEXT:    or a0, a0, a1
342; RV32I-WITHFP-NEXT:    seqz a0, a0
343; RV32I-WITHFP-NEXT:    lw s0, 8(sp)
344; RV32I-WITHFP-NEXT:    lw ra, 12(sp)
345; RV32I-WITHFP-NEXT:    addi sp, sp, 16
346; RV32I-WITHFP-NEXT:    ret
347  %j_bitcast = bitcast fp128 %j to i128
348  %1 = icmp eq i128 %h, %j_bitcast
349  %2 = zext i1 %1 to i32
350  ret i32 %2
351}
352
353define i32 @caller_large_scalars_exhausted_regs() nounwind {
354; RV32I-FPELIM-LABEL: caller_large_scalars_exhausted_regs:
355; RV32I-FPELIM:       # %bb.0:
356; RV32I-FPELIM-NEXT:    addi sp, sp, -64
357; RV32I-FPELIM-NEXT:    sw ra, 60(sp)
358; RV32I-FPELIM-NEXT:    addi a0, sp, 16
359; RV32I-FPELIM-NEXT:    sw a0, 4(sp)
360; RV32I-FPELIM-NEXT:    addi a0, zero, 9
361; RV32I-FPELIM-NEXT:    sw a0, 0(sp)
362; RV32I-FPELIM-NEXT:    lui a0, 524272
363; RV32I-FPELIM-NEXT:    sw a0, 28(sp)
364; RV32I-FPELIM-NEXT:    sw zero, 24(sp)
365; RV32I-FPELIM-NEXT:    sw zero, 20(sp)
366; RV32I-FPELIM-NEXT:    sw zero, 16(sp)
367; RV32I-FPELIM-NEXT:    sw zero, 52(sp)
368; RV32I-FPELIM-NEXT:    sw zero, 48(sp)
369; RV32I-FPELIM-NEXT:    sw zero, 44(sp)
370; RV32I-FPELIM-NEXT:    addi t0, zero, 8
371; RV32I-FPELIM-NEXT:    addi a0, zero, 1
372; RV32I-FPELIM-NEXT:    addi a1, zero, 2
373; RV32I-FPELIM-NEXT:    addi a2, zero, 3
374; RV32I-FPELIM-NEXT:    addi a3, zero, 4
375; RV32I-FPELIM-NEXT:    addi a4, zero, 5
376; RV32I-FPELIM-NEXT:    addi a5, zero, 6
377; RV32I-FPELIM-NEXT:    addi a6, zero, 7
378; RV32I-FPELIM-NEXT:    addi a7, sp, 40
379; RV32I-FPELIM-NEXT:    sw t0, 40(sp)
380; RV32I-FPELIM-NEXT:    call callee_large_scalars_exhausted_regs
381; RV32I-FPELIM-NEXT:    lw ra, 60(sp)
382; RV32I-FPELIM-NEXT:    addi sp, sp, 64
383; RV32I-FPELIM-NEXT:    ret
384;
385; RV32I-WITHFP-LABEL: caller_large_scalars_exhausted_regs:
386; RV32I-WITHFP:       # %bb.0:
387; RV32I-WITHFP-NEXT:    addi sp, sp, -64
388; RV32I-WITHFP-NEXT:    sw ra, 60(sp)
389; RV32I-WITHFP-NEXT:    sw s0, 56(sp)
390; RV32I-WITHFP-NEXT:    addi s0, sp, 64
391; RV32I-WITHFP-NEXT:    addi a0, s0, -48
392; RV32I-WITHFP-NEXT:    sw a0, 4(sp)
393; RV32I-WITHFP-NEXT:    addi a0, zero, 9
394; RV32I-WITHFP-NEXT:    sw a0, 0(sp)
395; RV32I-WITHFP-NEXT:    lui a0, 524272
396; RV32I-WITHFP-NEXT:    sw a0, -36(s0)
397; RV32I-WITHFP-NEXT:    sw zero, -40(s0)
398; RV32I-WITHFP-NEXT:    sw zero, -44(s0)
399; RV32I-WITHFP-NEXT:    sw zero, -48(s0)
400; RV32I-WITHFP-NEXT:    sw zero, -12(s0)
401; RV32I-WITHFP-NEXT:    sw zero, -16(s0)
402; RV32I-WITHFP-NEXT:    sw zero, -20(s0)
403; RV32I-WITHFP-NEXT:    addi t0, zero, 8
404; RV32I-WITHFP-NEXT:    addi a0, zero, 1
405; RV32I-WITHFP-NEXT:    addi a1, zero, 2
406; RV32I-WITHFP-NEXT:    addi a2, zero, 3
407; RV32I-WITHFP-NEXT:    addi a3, zero, 4
408; RV32I-WITHFP-NEXT:    addi a4, zero, 5
409; RV32I-WITHFP-NEXT:    addi a5, zero, 6
410; RV32I-WITHFP-NEXT:    addi a6, zero, 7
411; RV32I-WITHFP-NEXT:    addi a7, s0, -24
412; RV32I-WITHFP-NEXT:    sw t0, -24(s0)
413; RV32I-WITHFP-NEXT:    call callee_large_scalars_exhausted_regs
414; RV32I-WITHFP-NEXT:    lw s0, 56(sp)
415; RV32I-WITHFP-NEXT:    lw ra, 60(sp)
416; RV32I-WITHFP-NEXT:    addi sp, sp, 64
417; RV32I-WITHFP-NEXT:    ret
418  %1 = call i32 @callee_large_scalars_exhausted_regs(
419      i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i128 8, i32 9,
420      fp128 0xL00000000000000007FFF000000000000)
421  ret i32 %1
422}
423
424; Ensure that libcalls generated in the middle-end obey the calling convention
425
426define i32 @caller_mixed_scalar_libcalls(i64 %a) nounwind {
427; RV32I-FPELIM-LABEL: caller_mixed_scalar_libcalls:
428; RV32I-FPELIM:       # %bb.0:
429; RV32I-FPELIM-NEXT:    addi sp, sp, -32
430; RV32I-FPELIM-NEXT:    sw ra, 28(sp)
431; RV32I-FPELIM-NEXT:    mv a2, a1
432; RV32I-FPELIM-NEXT:    mv a1, a0
433; RV32I-FPELIM-NEXT:    addi a0, sp, 8
434; RV32I-FPELIM-NEXT:    call __floatditf
435; RV32I-FPELIM-NEXT:    lw a0, 8(sp)
436; RV32I-FPELIM-NEXT:    lw ra, 28(sp)
437; RV32I-FPELIM-NEXT:    addi sp, sp, 32
438; RV32I-FPELIM-NEXT:    ret
439;
440; RV32I-WITHFP-LABEL: caller_mixed_scalar_libcalls:
441; RV32I-WITHFP:       # %bb.0:
442; RV32I-WITHFP-NEXT:    addi sp, sp, -32
443; RV32I-WITHFP-NEXT:    sw ra, 28(sp)
444; RV32I-WITHFP-NEXT:    sw s0, 24(sp)
445; RV32I-WITHFP-NEXT:    addi s0, sp, 32
446; RV32I-WITHFP-NEXT:    mv a2, a1
447; RV32I-WITHFP-NEXT:    mv a1, a0
448; RV32I-WITHFP-NEXT:    addi a0, s0, -24
449; RV32I-WITHFP-NEXT:    call __floatditf
450; RV32I-WITHFP-NEXT:    lw a0, -24(s0)
451; RV32I-WITHFP-NEXT:    lw s0, 24(sp)
452; RV32I-WITHFP-NEXT:    lw ra, 28(sp)
453; RV32I-WITHFP-NEXT:    addi sp, sp, 32
454; RV32I-WITHFP-NEXT:    ret
455  %1 = sitofp i64 %a to fp128
456  %2 = bitcast fp128 %1 to i128
457  %3 = trunc i128 %2 to i32
458  ret i32 %3
459}
460
461; Check passing of coerced integer arrays
462
463%struct.small = type { i32, i32* }
464
465define i32 @callee_small_coerced_struct([2 x i32] %a.coerce) nounwind {
466; RV32I-FPELIM-LABEL: callee_small_coerced_struct:
467; RV32I-FPELIM:       # %bb.0:
468; RV32I-FPELIM-NEXT:    xor a0, a0, a1
469; RV32I-FPELIM-NEXT:    seqz a0, a0
470; RV32I-FPELIM-NEXT:    ret
471;
472; RV32I-WITHFP-LABEL: callee_small_coerced_struct:
473; RV32I-WITHFP:       # %bb.0:
474; RV32I-WITHFP-NEXT:    addi sp, sp, -16
475; RV32I-WITHFP-NEXT:    sw ra, 12(sp)
476; RV32I-WITHFP-NEXT:    sw s0, 8(sp)
477; RV32I-WITHFP-NEXT:    addi s0, sp, 16
478; RV32I-WITHFP-NEXT:    xor a0, a0, a1
479; RV32I-WITHFP-NEXT:    seqz a0, a0
480; RV32I-WITHFP-NEXT:    lw s0, 8(sp)
481; RV32I-WITHFP-NEXT:    lw ra, 12(sp)
482; RV32I-WITHFP-NEXT:    addi sp, sp, 16
483; RV32I-WITHFP-NEXT:    ret
484  %1 = extractvalue [2 x i32] %a.coerce, 0
485  %2 = extractvalue [2 x i32] %a.coerce, 1
486  %3 = icmp eq i32 %1, %2
487  %4 = zext i1 %3 to i32
488  ret i32 %4
489}
490
491define i32 @caller_small_coerced_struct() nounwind {
492; RV32I-FPELIM-LABEL: caller_small_coerced_struct:
493; RV32I-FPELIM:       # %bb.0:
494; RV32I-FPELIM-NEXT:    addi sp, sp, -16
495; RV32I-FPELIM-NEXT:    sw ra, 12(sp)
496; RV32I-FPELIM-NEXT:    addi a0, zero, 1
497; RV32I-FPELIM-NEXT:    addi a1, zero, 2
498; RV32I-FPELIM-NEXT:    call callee_small_coerced_struct
499; RV32I-FPELIM-NEXT:    lw ra, 12(sp)
500; RV32I-FPELIM-NEXT:    addi sp, sp, 16
501; RV32I-FPELIM-NEXT:    ret
502;
503; RV32I-WITHFP-LABEL: caller_small_coerced_struct:
504; RV32I-WITHFP:       # %bb.0:
505; RV32I-WITHFP-NEXT:    addi sp, sp, -16
506; RV32I-WITHFP-NEXT:    sw ra, 12(sp)
507; RV32I-WITHFP-NEXT:    sw s0, 8(sp)
508; RV32I-WITHFP-NEXT:    addi s0, sp, 16
509; RV32I-WITHFP-NEXT:    addi a0, zero, 1
510; RV32I-WITHFP-NEXT:    addi a1, zero, 2
511; RV32I-WITHFP-NEXT:    call callee_small_coerced_struct
512; RV32I-WITHFP-NEXT:    lw s0, 8(sp)
513; RV32I-WITHFP-NEXT:    lw ra, 12(sp)
514; RV32I-WITHFP-NEXT:    addi sp, sp, 16
515; RV32I-WITHFP-NEXT:    ret
516  %1 = call i32 @callee_small_coerced_struct([2 x i32] [i32 1, i32 2])
517  ret i32 %1
518}
519
520; Check large struct arguments, which are passed byval
521
522%struct.large = type { i32, i32, i32, i32 }
523
524define i32 @callee_large_struct(%struct.large* byval(%struct.large) align 4 %a) nounwind {
525; RV32I-FPELIM-LABEL: callee_large_struct:
526; RV32I-FPELIM:       # %bb.0:
527; RV32I-FPELIM-NEXT:    lw a1, 0(a0)
528; RV32I-FPELIM-NEXT:    lw a0, 12(a0)
529; RV32I-FPELIM-NEXT:    add a0, a1, a0
530; RV32I-FPELIM-NEXT:    ret
531;
532; RV32I-WITHFP-LABEL: callee_large_struct:
533; RV32I-WITHFP:       # %bb.0:
534; RV32I-WITHFP-NEXT:    addi sp, sp, -16
535; RV32I-WITHFP-NEXT:    sw ra, 12(sp)
536; RV32I-WITHFP-NEXT:    sw s0, 8(sp)
537; RV32I-WITHFP-NEXT:    addi s0, sp, 16
538; RV32I-WITHFP-NEXT:    lw a1, 0(a0)
539; RV32I-WITHFP-NEXT:    lw a0, 12(a0)
540; RV32I-WITHFP-NEXT:    add a0, a1, a0
541; RV32I-WITHFP-NEXT:    lw s0, 8(sp)
542; RV32I-WITHFP-NEXT:    lw ra, 12(sp)
543; RV32I-WITHFP-NEXT:    addi sp, sp, 16
544; RV32I-WITHFP-NEXT:    ret
545  %1 = getelementptr inbounds %struct.large, %struct.large* %a, i32 0, i32 0
546  %2 = getelementptr inbounds %struct.large, %struct.large* %a, i32 0, i32 3
547  %3 = load i32, i32* %1
548  %4 = load i32, i32* %2
549  %5 = add i32 %3, %4
550  ret i32 %5
551}
552
553define i32 @caller_large_struct() nounwind {
554; RV32I-FPELIM-LABEL: caller_large_struct:
555; RV32I-FPELIM:       # %bb.0:
556; RV32I-FPELIM-NEXT:    addi sp, sp, -48
557; RV32I-FPELIM-NEXT:    sw ra, 44(sp)
558; RV32I-FPELIM-NEXT:    addi a0, zero, 1
559; RV32I-FPELIM-NEXT:    sw a0, 24(sp)
560; RV32I-FPELIM-NEXT:    addi a1, zero, 2
561; RV32I-FPELIM-NEXT:    sw a1, 28(sp)
562; RV32I-FPELIM-NEXT:    addi a2, zero, 3
563; RV32I-FPELIM-NEXT:    sw a2, 32(sp)
564; RV32I-FPELIM-NEXT:    addi a3, zero, 4
565; RV32I-FPELIM-NEXT:    sw a3, 36(sp)
566; RV32I-FPELIM-NEXT:    sw a0, 8(sp)
567; RV32I-FPELIM-NEXT:    sw a1, 12(sp)
568; RV32I-FPELIM-NEXT:    sw a2, 16(sp)
569; RV32I-FPELIM-NEXT:    sw a3, 20(sp)
570; RV32I-FPELIM-NEXT:    addi a0, sp, 8
571; RV32I-FPELIM-NEXT:    call callee_large_struct
572; RV32I-FPELIM-NEXT:    lw ra, 44(sp)
573; RV32I-FPELIM-NEXT:    addi sp, sp, 48
574; RV32I-FPELIM-NEXT:    ret
575;
576; RV32I-WITHFP-LABEL: caller_large_struct:
577; RV32I-WITHFP:       # %bb.0:
578; RV32I-WITHFP-NEXT:    addi sp, sp, -48
579; RV32I-WITHFP-NEXT:    sw ra, 44(sp)
580; RV32I-WITHFP-NEXT:    sw s0, 40(sp)
581; RV32I-WITHFP-NEXT:    addi s0, sp, 48
582; RV32I-WITHFP-NEXT:    addi a0, zero, 1
583; RV32I-WITHFP-NEXT:    sw a0, -24(s0)
584; RV32I-WITHFP-NEXT:    addi a1, zero, 2
585; RV32I-WITHFP-NEXT:    sw a1, -20(s0)
586; RV32I-WITHFP-NEXT:    addi a2, zero, 3
587; RV32I-WITHFP-NEXT:    sw a2, -16(s0)
588; RV32I-WITHFP-NEXT:    addi a3, zero, 4
589; RV32I-WITHFP-NEXT:    sw a3, -12(s0)
590; RV32I-WITHFP-NEXT:    sw a0, -40(s0)
591; RV32I-WITHFP-NEXT:    sw a1, -36(s0)
592; RV32I-WITHFP-NEXT:    sw a2, -32(s0)
593; RV32I-WITHFP-NEXT:    sw a3, -28(s0)
594; RV32I-WITHFP-NEXT:    addi a0, s0, -40
595; RV32I-WITHFP-NEXT:    call callee_large_struct
596; RV32I-WITHFP-NEXT:    lw s0, 40(sp)
597; RV32I-WITHFP-NEXT:    lw ra, 44(sp)
598; RV32I-WITHFP-NEXT:    addi sp, sp, 48
599; RV32I-WITHFP-NEXT:    ret
600  %ls = alloca %struct.large, align 4
601  %1 = bitcast %struct.large* %ls to i8*
602  %a = getelementptr inbounds %struct.large, %struct.large* %ls, i32 0, i32 0
603  store i32 1, i32* %a
604  %b = getelementptr inbounds %struct.large, %struct.large* %ls, i32 0, i32 1
605  store i32 2, i32* %b
606  %c = getelementptr inbounds %struct.large, %struct.large* %ls, i32 0, i32 2
607  store i32 3, i32* %c
608  %d = getelementptr inbounds %struct.large, %struct.large* %ls, i32 0, i32 3
609  store i32 4, i32* %d
610  %2 = call i32 @callee_large_struct(%struct.large* byval(%struct.large) align 4 %ls)
611  ret i32 %2
612}
613
614; Check 2x*xlen values are aligned appropriately when passed on the stack
615; Must keep define on a single line due to an update_llc_test_checks.py limitation
616define i32 @callee_aligned_stack(i32 %a, i32 %b, fp128 %c, i32 %d, i32 %e, i64 %f, i32 %g, i32 %h, i64 %i, i32 %j, [2 x i32] %k) nounwind {
617; The i64 should be 8-byte aligned on the stack, but the two-element array
618; should only be 4-byte aligned
619; RV32I-FPELIM-LABEL: callee_aligned_stack:
620; RV32I-FPELIM:       # %bb.0:
621; RV32I-FPELIM-NEXT:    lw a0, 0(a2)
622; RV32I-FPELIM-NEXT:    lw a1, 20(sp)
623; RV32I-FPELIM-NEXT:    lw a2, 0(sp)
624; RV32I-FPELIM-NEXT:    lw a3, 8(sp)
625; RV32I-FPELIM-NEXT:    lw a4, 16(sp)
626; RV32I-FPELIM-NEXT:    add a0, a0, a7
627; RV32I-FPELIM-NEXT:    add a0, a0, a2
628; RV32I-FPELIM-NEXT:    add a0, a0, a3
629; RV32I-FPELIM-NEXT:    add a0, a0, a4
630; RV32I-FPELIM-NEXT:    add a0, a0, a1
631; RV32I-FPELIM-NEXT:    ret
632;
633; RV32I-WITHFP-LABEL: callee_aligned_stack:
634; RV32I-WITHFP:       # %bb.0:
635; RV32I-WITHFP-NEXT:    addi sp, sp, -16
636; RV32I-WITHFP-NEXT:    sw ra, 12(sp)
637; RV32I-WITHFP-NEXT:    sw s0, 8(sp)
638; RV32I-WITHFP-NEXT:    addi s0, sp, 16
639; RV32I-WITHFP-NEXT:    lw a0, 0(a2)
640; RV32I-WITHFP-NEXT:    lw a1, 20(s0)
641; RV32I-WITHFP-NEXT:    lw a2, 0(s0)
642; RV32I-WITHFP-NEXT:    lw a3, 8(s0)
643; RV32I-WITHFP-NEXT:    lw a4, 16(s0)
644; RV32I-WITHFP-NEXT:    add a0, a0, a7
645; RV32I-WITHFP-NEXT:    add a0, a0, a2
646; RV32I-WITHFP-NEXT:    add a0, a0, a3
647; RV32I-WITHFP-NEXT:    add a0, a0, a4
648; RV32I-WITHFP-NEXT:    add a0, a0, a1
649; RV32I-WITHFP-NEXT:    lw s0, 8(sp)
650; RV32I-WITHFP-NEXT:    lw ra, 12(sp)
651; RV32I-WITHFP-NEXT:    addi sp, sp, 16
652; RV32I-WITHFP-NEXT:    ret
653  %1 = bitcast fp128 %c to i128
654  %2 = trunc i128 %1 to i32
655  %3 = add i32 %2, %g
656  %4 = add i32 %3, %h
657  %5 = trunc i64 %i to i32
658  %6 = add i32 %4, %5
659  %7 = add i32 %6, %j
660  %8 = extractvalue [2 x i32] %k, 0
661  %9 = add i32 %7, %8
662  ret i32 %9
663}
664
665define void @caller_aligned_stack() nounwind {
666; The i64 should be 8-byte aligned on the stack, but the two-element array
667; should only be 4-byte aligned
668; RV32I-FPELIM-LABEL: caller_aligned_stack:
669; RV32I-FPELIM:       # %bb.0:
670; RV32I-FPELIM-NEXT:    addi sp, sp, -64
671; RV32I-FPELIM-NEXT:    sw ra, 60(sp)
672; RV32I-FPELIM-NEXT:    addi a0, zero, 19
673; RV32I-FPELIM-NEXT:    sw a0, 24(sp)
674; RV32I-FPELIM-NEXT:    addi a0, zero, 18
675; RV32I-FPELIM-NEXT:    sw a0, 20(sp)
676; RV32I-FPELIM-NEXT:    addi a0, zero, 17
677; RV32I-FPELIM-NEXT:    sw a0, 16(sp)
678; RV32I-FPELIM-NEXT:    sw zero, 12(sp)
679; RV32I-FPELIM-NEXT:    addi a0, zero, 16
680; RV32I-FPELIM-NEXT:    sw a0, 8(sp)
681; RV32I-FPELIM-NEXT:    addi a0, zero, 15
682; RV32I-FPELIM-NEXT:    sw a0, 0(sp)
683; RV32I-FPELIM-NEXT:    lui a0, 262153
684; RV32I-FPELIM-NEXT:    addi a0, a0, 491
685; RV32I-FPELIM-NEXT:    sw a0, 44(sp)
686; RV32I-FPELIM-NEXT:    lui a0, 545260
687; RV32I-FPELIM-NEXT:    addi a0, a0, -1967
688; RV32I-FPELIM-NEXT:    sw a0, 40(sp)
689; RV32I-FPELIM-NEXT:    lui a0, 964690
690; RV32I-FPELIM-NEXT:    addi a0, a0, -328
691; RV32I-FPELIM-NEXT:    sw a0, 36(sp)
692; RV32I-FPELIM-NEXT:    lui a0, 335544
693; RV32I-FPELIM-NEXT:    addi t0, a0, 1311
694; RV32I-FPELIM-NEXT:    lui a0, 688509
695; RV32I-FPELIM-NEXT:    addi a5, a0, -2048
696; RV32I-FPELIM-NEXT:    addi a0, zero, 1
697; RV32I-FPELIM-NEXT:    addi a1, zero, 11
698; RV32I-FPELIM-NEXT:    addi a2, sp, 32
699; RV32I-FPELIM-NEXT:    addi a3, zero, 12
700; RV32I-FPELIM-NEXT:    addi a4, zero, 13
701; RV32I-FPELIM-NEXT:    addi a6, zero, 4
702; RV32I-FPELIM-NEXT:    addi a7, zero, 14
703; RV32I-FPELIM-NEXT:    sw t0, 32(sp)
704; RV32I-FPELIM-NEXT:    call callee_aligned_stack
705; RV32I-FPELIM-NEXT:    lw ra, 60(sp)
706; RV32I-FPELIM-NEXT:    addi sp, sp, 64
707; RV32I-FPELIM-NEXT:    ret
708;
709; RV32I-WITHFP-LABEL: caller_aligned_stack:
710; RV32I-WITHFP:       # %bb.0:
711; RV32I-WITHFP-NEXT:    addi sp, sp, -64
712; RV32I-WITHFP-NEXT:    sw ra, 60(sp)
713; RV32I-WITHFP-NEXT:    sw s0, 56(sp)
714; RV32I-WITHFP-NEXT:    addi s0, sp, 64
715; RV32I-WITHFP-NEXT:    addi a0, zero, 19
716; RV32I-WITHFP-NEXT:    sw a0, 24(sp)
717; RV32I-WITHFP-NEXT:    addi a0, zero, 18
718; RV32I-WITHFP-NEXT:    sw a0, 20(sp)
719; RV32I-WITHFP-NEXT:    addi a0, zero, 17
720; RV32I-WITHFP-NEXT:    sw a0, 16(sp)
721; RV32I-WITHFP-NEXT:    sw zero, 12(sp)
722; RV32I-WITHFP-NEXT:    addi a0, zero, 16
723; RV32I-WITHFP-NEXT:    sw a0, 8(sp)
724; RV32I-WITHFP-NEXT:    addi a0, zero, 15
725; RV32I-WITHFP-NEXT:    sw a0, 0(sp)
726; RV32I-WITHFP-NEXT:    lui a0, 262153
727; RV32I-WITHFP-NEXT:    addi a0, a0, 491
728; RV32I-WITHFP-NEXT:    sw a0, -20(s0)
729; RV32I-WITHFP-NEXT:    lui a0, 545260
730; RV32I-WITHFP-NEXT:    addi a0, a0, -1967
731; RV32I-WITHFP-NEXT:    sw a0, -24(s0)
732; RV32I-WITHFP-NEXT:    lui a0, 964690
733; RV32I-WITHFP-NEXT:    addi a0, a0, -328
734; RV32I-WITHFP-NEXT:    sw a0, -28(s0)
735; RV32I-WITHFP-NEXT:    lui a0, 335544
736; RV32I-WITHFP-NEXT:    addi t0, a0, 1311
737; RV32I-WITHFP-NEXT:    lui a0, 688509
738; RV32I-WITHFP-NEXT:    addi a5, a0, -2048
739; RV32I-WITHFP-NEXT:    addi a0, zero, 1
740; RV32I-WITHFP-NEXT:    addi a1, zero, 11
741; RV32I-WITHFP-NEXT:    addi a2, s0, -32
742; RV32I-WITHFP-NEXT:    addi a3, zero, 12
743; RV32I-WITHFP-NEXT:    addi a4, zero, 13
744; RV32I-WITHFP-NEXT:    addi a6, zero, 4
745; RV32I-WITHFP-NEXT:    addi a7, zero, 14
746; RV32I-WITHFP-NEXT:    sw t0, -32(s0)
747; RV32I-WITHFP-NEXT:    call callee_aligned_stack
748; RV32I-WITHFP-NEXT:    lw s0, 56(sp)
749; RV32I-WITHFP-NEXT:    lw ra, 60(sp)
750; RV32I-WITHFP-NEXT:    addi sp, sp, 64
751; RV32I-WITHFP-NEXT:    ret
752  %1 = call i32 @callee_aligned_stack(i32 1, i32 11,
753    fp128 0xLEB851EB851EB851F400091EB851EB851, i32 12, i32 13,
754    i64 20000000000, i32 14, i32 15, i64 16, i32 17,
755    [2 x i32] [i32 18, i32 19])
756  ret void
757}
758
759; Check return of 2x xlen scalars
760
761define i64 @callee_small_scalar_ret() nounwind {
762; RV32I-FPELIM-LABEL: callee_small_scalar_ret:
763; RV32I-FPELIM:       # %bb.0:
764; RV32I-FPELIM-NEXT:    lui a0, 466866
765; RV32I-FPELIM-NEXT:    addi a0, a0, 1677
766; RV32I-FPELIM-NEXT:    addi a1, zero, 287
767; RV32I-FPELIM-NEXT:    ret
768;
769; RV32I-WITHFP-LABEL: callee_small_scalar_ret:
770; RV32I-WITHFP:       # %bb.0:
771; RV32I-WITHFP-NEXT:    addi sp, sp, -16
772; RV32I-WITHFP-NEXT:    sw ra, 12(sp)
773; RV32I-WITHFP-NEXT:    sw s0, 8(sp)
774; RV32I-WITHFP-NEXT:    addi s0, sp, 16
775; RV32I-WITHFP-NEXT:    lui a0, 466866
776; RV32I-WITHFP-NEXT:    addi a0, a0, 1677
777; RV32I-WITHFP-NEXT:    addi a1, zero, 287
778; RV32I-WITHFP-NEXT:    lw s0, 8(sp)
779; RV32I-WITHFP-NEXT:    lw ra, 12(sp)
780; RV32I-WITHFP-NEXT:    addi sp, sp, 16
781; RV32I-WITHFP-NEXT:    ret
782  ret i64 1234567898765
783}
784
785define i32 @caller_small_scalar_ret() nounwind {
786; RV32I-FPELIM-LABEL: caller_small_scalar_ret:
787; RV32I-FPELIM:       # %bb.0:
788; RV32I-FPELIM-NEXT:    addi sp, sp, -16
789; RV32I-FPELIM-NEXT:    sw ra, 12(sp)
790; RV32I-FPELIM-NEXT:    call callee_small_scalar_ret
791; RV32I-FPELIM-NEXT:    lui a2, 56
792; RV32I-FPELIM-NEXT:    addi a2, a2, 580
793; RV32I-FPELIM-NEXT:    xor a1, a1, a2
794; RV32I-FPELIM-NEXT:    lui a2, 200614
795; RV32I-FPELIM-NEXT:    addi a2, a2, 647
796; RV32I-FPELIM-NEXT:    xor a0, a0, a2
797; RV32I-FPELIM-NEXT:    or a0, a0, a1
798; RV32I-FPELIM-NEXT:    seqz a0, a0
799; RV32I-FPELIM-NEXT:    lw ra, 12(sp)
800; RV32I-FPELIM-NEXT:    addi sp, sp, 16
801; RV32I-FPELIM-NEXT:    ret
802;
803; RV32I-WITHFP-LABEL: caller_small_scalar_ret:
804; RV32I-WITHFP:       # %bb.0:
805; RV32I-WITHFP-NEXT:    addi sp, sp, -16
806; RV32I-WITHFP-NEXT:    sw ra, 12(sp)
807; RV32I-WITHFP-NEXT:    sw s0, 8(sp)
808; RV32I-WITHFP-NEXT:    addi s0, sp, 16
809; RV32I-WITHFP-NEXT:    call callee_small_scalar_ret
810; RV32I-WITHFP-NEXT:    lui a2, 56
811; RV32I-WITHFP-NEXT:    addi a2, a2, 580
812; RV32I-WITHFP-NEXT:    xor a1, a1, a2
813; RV32I-WITHFP-NEXT:    lui a2, 200614
814; RV32I-WITHFP-NEXT:    addi a2, a2, 647
815; RV32I-WITHFP-NEXT:    xor a0, a0, a2
816; RV32I-WITHFP-NEXT:    or a0, a0, a1
817; RV32I-WITHFP-NEXT:    seqz a0, a0
818; RV32I-WITHFP-NEXT:    lw s0, 8(sp)
819; RV32I-WITHFP-NEXT:    lw ra, 12(sp)
820; RV32I-WITHFP-NEXT:    addi sp, sp, 16
821; RV32I-WITHFP-NEXT:    ret
822  %1 = call i64 @callee_small_scalar_ret()
823  %2 = icmp eq i64 987654321234567, %1
824  %3 = zext i1 %2 to i32
825  ret i32 %3
826}
827
828; Check return of 2x xlen structs
829
830define %struct.small @callee_small_struct_ret() nounwind {
831; RV32I-FPELIM-LABEL: callee_small_struct_ret:
832; RV32I-FPELIM:       # %bb.0:
833; RV32I-FPELIM-NEXT:    addi a0, zero, 1
834; RV32I-FPELIM-NEXT:    mv a1, zero
835; RV32I-FPELIM-NEXT:    ret
836;
837; RV32I-WITHFP-LABEL: callee_small_struct_ret:
838; RV32I-WITHFP:       # %bb.0:
839; RV32I-WITHFP-NEXT:    addi sp, sp, -16
840; RV32I-WITHFP-NEXT:    sw ra, 12(sp)
841; RV32I-WITHFP-NEXT:    sw s0, 8(sp)
842; RV32I-WITHFP-NEXT:    addi s0, sp, 16
843; RV32I-WITHFP-NEXT:    addi a0, zero, 1
844; RV32I-WITHFP-NEXT:    mv a1, zero
845; RV32I-WITHFP-NEXT:    lw s0, 8(sp)
846; RV32I-WITHFP-NEXT:    lw ra, 12(sp)
847; RV32I-WITHFP-NEXT:    addi sp, sp, 16
848; RV32I-WITHFP-NEXT:    ret
849  ret %struct.small { i32 1, i32* null }
850}
851
852define i32 @caller_small_struct_ret() nounwind {
853; RV32I-FPELIM-LABEL: caller_small_struct_ret:
854; RV32I-FPELIM:       # %bb.0:
855; RV32I-FPELIM-NEXT:    addi sp, sp, -16
856; RV32I-FPELIM-NEXT:    sw ra, 12(sp)
857; RV32I-FPELIM-NEXT:    call callee_small_struct_ret
858; RV32I-FPELIM-NEXT:    add a0, a0, a1
859; RV32I-FPELIM-NEXT:    lw ra, 12(sp)
860; RV32I-FPELIM-NEXT:    addi sp, sp, 16
861; RV32I-FPELIM-NEXT:    ret
862;
863; RV32I-WITHFP-LABEL: caller_small_struct_ret:
864; RV32I-WITHFP:       # %bb.0:
865; RV32I-WITHFP-NEXT:    addi sp, sp, -16
866; RV32I-WITHFP-NEXT:    sw ra, 12(sp)
867; RV32I-WITHFP-NEXT:    sw s0, 8(sp)
868; RV32I-WITHFP-NEXT:    addi s0, sp, 16
869; RV32I-WITHFP-NEXT:    call callee_small_struct_ret
870; RV32I-WITHFP-NEXT:    add a0, a0, a1
871; RV32I-WITHFP-NEXT:    lw s0, 8(sp)
872; RV32I-WITHFP-NEXT:    lw ra, 12(sp)
873; RV32I-WITHFP-NEXT:    addi sp, sp, 16
874; RV32I-WITHFP-NEXT:    ret
875  %1 = call %struct.small @callee_small_struct_ret()
876  %2 = extractvalue %struct.small %1, 0
877  %3 = extractvalue %struct.small %1, 1
878  %4 = ptrtoint i32* %3 to i32
879  %5 = add i32 %2, %4
880  ret i32 %5
881}
882
883; Check return of >2x xlen scalars
884
885define fp128 @callee_large_scalar_ret() nounwind {
886; RV32I-FPELIM-LABEL: callee_large_scalar_ret:
887; RV32I-FPELIM:       # %bb.0:
888; RV32I-FPELIM-NEXT:    lui a1, 524272
889; RV32I-FPELIM-NEXT:    sw a1, 12(a0)
890; RV32I-FPELIM-NEXT:    sw zero, 8(a0)
891; RV32I-FPELIM-NEXT:    sw zero, 4(a0)
892; RV32I-FPELIM-NEXT:    sw zero, 0(a0)
893; RV32I-FPELIM-NEXT:    ret
894;
895; RV32I-WITHFP-LABEL: callee_large_scalar_ret:
896; RV32I-WITHFP:       # %bb.0:
897; RV32I-WITHFP-NEXT:    addi sp, sp, -16
898; RV32I-WITHFP-NEXT:    sw ra, 12(sp)
899; RV32I-WITHFP-NEXT:    sw s0, 8(sp)
900; RV32I-WITHFP-NEXT:    addi s0, sp, 16
901; RV32I-WITHFP-NEXT:    lui a1, 524272
902; RV32I-WITHFP-NEXT:    sw a1, 12(a0)
903; RV32I-WITHFP-NEXT:    sw zero, 8(a0)
904; RV32I-WITHFP-NEXT:    sw zero, 4(a0)
905; RV32I-WITHFP-NEXT:    sw zero, 0(a0)
906; RV32I-WITHFP-NEXT:    lw s0, 8(sp)
907; RV32I-WITHFP-NEXT:    lw ra, 12(sp)
908; RV32I-WITHFP-NEXT:    addi sp, sp, 16
909; RV32I-WITHFP-NEXT:    ret
910  ret fp128 0xL00000000000000007FFF000000000000
911}
912
913define void @caller_large_scalar_ret() nounwind {
914; RV32I-FPELIM-LABEL: caller_large_scalar_ret:
915; RV32I-FPELIM:       # %bb.0:
916; RV32I-FPELIM-NEXT:    addi sp, sp, -32
917; RV32I-FPELIM-NEXT:    sw ra, 28(sp)
918; RV32I-FPELIM-NEXT:    mv a0, sp
919; RV32I-FPELIM-NEXT:    call callee_large_scalar_ret
920; RV32I-FPELIM-NEXT:    lw ra, 28(sp)
921; RV32I-FPELIM-NEXT:    addi sp, sp, 32
922; RV32I-FPELIM-NEXT:    ret
923;
924; RV32I-WITHFP-LABEL: caller_large_scalar_ret:
925; RV32I-WITHFP:       # %bb.0:
926; RV32I-WITHFP-NEXT:    addi sp, sp, -32
927; RV32I-WITHFP-NEXT:    sw ra, 28(sp)
928; RV32I-WITHFP-NEXT:    sw s0, 24(sp)
929; RV32I-WITHFP-NEXT:    addi s0, sp, 32
930; RV32I-WITHFP-NEXT:    addi a0, s0, -32
931; RV32I-WITHFP-NEXT:    call callee_large_scalar_ret
932; RV32I-WITHFP-NEXT:    lw s0, 24(sp)
933; RV32I-WITHFP-NEXT:    lw ra, 28(sp)
934; RV32I-WITHFP-NEXT:    addi sp, sp, 32
935; RV32I-WITHFP-NEXT:    ret
936  %1 = call fp128 @callee_large_scalar_ret()
937  ret void
938}
939
940; Check return of >2x xlen structs
941
942define void @callee_large_struct_ret(%struct.large* noalias sret(%struct.large) %agg.result) nounwind {
943; RV32I-FPELIM-LABEL: callee_large_struct_ret:
944; RV32I-FPELIM:       # %bb.0:
945; RV32I-FPELIM-NEXT:    addi a1, zero, 1
946; RV32I-FPELIM-NEXT:    sw a1, 0(a0)
947; RV32I-FPELIM-NEXT:    addi a1, zero, 2
948; RV32I-FPELIM-NEXT:    sw a1, 4(a0)
949; RV32I-FPELIM-NEXT:    addi a1, zero, 3
950; RV32I-FPELIM-NEXT:    sw a1, 8(a0)
951; RV32I-FPELIM-NEXT:    addi a1, zero, 4
952; RV32I-FPELIM-NEXT:    sw a1, 12(a0)
953; RV32I-FPELIM-NEXT:    ret
954;
955; RV32I-WITHFP-LABEL: callee_large_struct_ret:
956; RV32I-WITHFP:       # %bb.0:
957; RV32I-WITHFP-NEXT:    addi sp, sp, -16
958; RV32I-WITHFP-NEXT:    sw ra, 12(sp)
959; RV32I-WITHFP-NEXT:    sw s0, 8(sp)
960; RV32I-WITHFP-NEXT:    addi s0, sp, 16
961; RV32I-WITHFP-NEXT:    addi a1, zero, 1
962; RV32I-WITHFP-NEXT:    sw a1, 0(a0)
963; RV32I-WITHFP-NEXT:    addi a1, zero, 2
964; RV32I-WITHFP-NEXT:    sw a1, 4(a0)
965; RV32I-WITHFP-NEXT:    addi a1, zero, 3
966; RV32I-WITHFP-NEXT:    sw a1, 8(a0)
967; RV32I-WITHFP-NEXT:    addi a1, zero, 4
968; RV32I-WITHFP-NEXT:    sw a1, 12(a0)
969; RV32I-WITHFP-NEXT:    lw s0, 8(sp)
970; RV32I-WITHFP-NEXT:    lw ra, 12(sp)
971; RV32I-WITHFP-NEXT:    addi sp, sp, 16
972; RV32I-WITHFP-NEXT:    ret
973  %a = getelementptr inbounds %struct.large, %struct.large* %agg.result, i32 0, i32 0
974  store i32 1, i32* %a, align 4
975  %b = getelementptr inbounds %struct.large, %struct.large* %agg.result, i32 0, i32 1
976  store i32 2, i32* %b, align 4
977  %c = getelementptr inbounds %struct.large, %struct.large* %agg.result, i32 0, i32 2
978  store i32 3, i32* %c, align 4
979  %d = getelementptr inbounds %struct.large, %struct.large* %agg.result, i32 0, i32 3
980  store i32 4, i32* %d, align 4
981  ret void
982}
983
984define i32 @caller_large_struct_ret() nounwind {
985; RV32I-FPELIM-LABEL: caller_large_struct_ret:
986; RV32I-FPELIM:       # %bb.0:
987; RV32I-FPELIM-NEXT:    addi sp, sp, -32
988; RV32I-FPELIM-NEXT:    sw ra, 28(sp)
989; RV32I-FPELIM-NEXT:    addi a0, sp, 8
990; RV32I-FPELIM-NEXT:    call callee_large_struct_ret
991; RV32I-FPELIM-NEXT:    lw a0, 8(sp)
992; RV32I-FPELIM-NEXT:    lw a1, 20(sp)
993; RV32I-FPELIM-NEXT:    add a0, a0, a1
994; RV32I-FPELIM-NEXT:    lw ra, 28(sp)
995; RV32I-FPELIM-NEXT:    addi sp, sp, 32
996; RV32I-FPELIM-NEXT:    ret
997;
998; RV32I-WITHFP-LABEL: caller_large_struct_ret:
999; RV32I-WITHFP:       # %bb.0:
1000; RV32I-WITHFP-NEXT:    addi sp, sp, -32
1001; RV32I-WITHFP-NEXT:    sw ra, 28(sp)
1002; RV32I-WITHFP-NEXT:    sw s0, 24(sp)
1003; RV32I-WITHFP-NEXT:    addi s0, sp, 32
1004; RV32I-WITHFP-NEXT:    addi a0, s0, -24
1005; RV32I-WITHFP-NEXT:    call callee_large_struct_ret
1006; RV32I-WITHFP-NEXT:    lw a0, -24(s0)
1007; RV32I-WITHFP-NEXT:    lw a1, -12(s0)
1008; RV32I-WITHFP-NEXT:    add a0, a0, a1
1009; RV32I-WITHFP-NEXT:    lw s0, 24(sp)
1010; RV32I-WITHFP-NEXT:    lw ra, 28(sp)
1011; RV32I-WITHFP-NEXT:    addi sp, sp, 32
1012; RV32I-WITHFP-NEXT:    ret
1013  %1 = alloca %struct.large
1014  call void @callee_large_struct_ret(%struct.large* sret(%struct.large) %1)
1015  %2 = getelementptr inbounds %struct.large, %struct.large* %1, i32 0, i32 0
1016  %3 = load i32, i32* %2
1017  %4 = getelementptr inbounds %struct.large, %struct.large* %1, i32 0, i32 3
1018  %5 = load i32, i32* %4
1019  %6 = add i32 %3, %5
1020  ret i32 %6
1021}
1022