1; RUN: llc < %s -march=sparc -disable-sparc-delay-filler -disable-sparc-leaf-proc | FileCheck %s --check-prefix=CHECK --check-prefix=HARD --check-prefix=CHECK-BE
2; RUN: llc < %s -march=sparcel -disable-sparc-delay-filler -disable-sparc-leaf-proc | FileCheck %s --check-prefix=CHECK --check-prefix=HARD --check-prefix=CHECK-LE
3; RUN: llc < %s -march=sparc -disable-sparc-delay-filler -disable-sparc-leaf-proc -mattr=soft-float | FileCheck %s --check-prefix=CHECK --check-prefix=SOFT --check-prefix=CHECK-BE
4
5; CHECK-LABEL: intarg:
6; The save/restore frame is not strictly necessary here, but we would need to
7; refer to %o registers instead.
8; CHECK: save %sp, -96, %sp
9; CHECK: ld [%fp+96], [[R2:%[gilo][0-7]]]
10; CHECK: ld [%fp+92], [[R1:%[gilo][0-7]]]
11; CHECK: stb %i0, [%i4]
12; CHECK: stb %i1, [%i4]
13; CHECK: sth %i2, [%i4]
14; CHECK: st  %i3, [%i4]
15; CHECK: st  %i4, [%i4]
16; CHECK: st  %i5, [%i4]
17; CHECK: st  [[R1]], [%i4]
18; CHECK: st  [[R2]], [%i4]
19; CHECK: restore
20define void @intarg(i8  %a0,   ; %i0
21                    i8  %a1,   ; %i1
22                    i16 %a2,   ; %i2
23                    i32 %a3,   ; %i3
24                    i8* %a4,   ; %i4
25                    i32 %a5,   ; %i5
26                    i32 signext %a6,   ; [%fp+92]
27                    i8* %a7) { ; [%fp+96]
28  store i8 %a0, i8* %a4
29  store i8 %a1, i8* %a4
30  %p16 = bitcast i8* %a4 to i16*
31  store i16 %a2, i16* %p16
32  %p32 = bitcast i8* %a4 to i32*
33  store i32 %a3, i32* %p32
34  %pp = bitcast i8* %a4 to i8**
35  store i8* %a4, i8** %pp
36  store i32 %a5, i32* %p32
37  store i32 %a6, i32* %p32
38  store i8* %a7, i8** %pp
39  ret void
40}
41
42; CHECK-LABEL: call_intarg:
43; CHECK: save %sp, -104, %sp
44; Use %o0-%o5 for outgoing arguments
45; CHECK: mov 5, %o5
46; CHECK: st %i0, [%sp+92]
47; CHECK: call intarg
48; CHECK-NOT: add %sp
49; CHECK: restore
50define void @call_intarg(i32 %i0, i8* %i1) {
51  call void @intarg(i8 0, i8 1, i16 2, i32 3, i8* undef, i32 5, i32 %i0, i8* %i1)
52  ret void
53}
54
55;; Verify doubles starting with an even reg, starting with an odd reg,
56;; straddling the boundary of regs and mem, and floats in regs and mem.
57;
58; CHECK-LABEL: floatarg:
59; HARD: save %sp, -120, %sp
60; HARD: mov %i5, %g2
61; HARD-NEXT: ld [%fp+92], %g3
62; HARD-NEXT: mov %i4, %i5
63; HARD-NEXT: std %g2, [%fp+-24]
64; HARD-NEXT: mov %i3, %i4
65; HARD-NEXT: std %i4, [%fp+-16]
66; HARD-NEXT: std %i0, [%fp+-8]
67; HARD-NEXT: st %i2, [%fp+-28]
68; HARD-NEXT: ld [%fp+104], %f0
69; HARD-NEXT: ldd [%fp+96], %f2
70; HARD-NEXT: ld [%fp+-28], %f1
71; HARD-NEXT: ldd [%fp+-8], %f4
72; HARD-NEXT: ldd [%fp+-16], %f6
73; HARD-NEXT: ldd [%fp+-24], %f8
74; HARD-NEXT: fstod %f1, %f10
75; HARD-NEXT: faddd %f4, %f10, %f4
76; HARD-NEXT: faddd %f6, %f4, %f4
77; HARD-NEXT: faddd %f8, %f4, %f4
78; HARD-NEXT: faddd %f2, %f4, %f2
79; HARD-NEXT: fstod %f0, %f0
80; HARD-NEXT: faddd %f0, %f2, %f0
81; SOFT: save %sp, -96, %sp
82; SOFT: ld [%fp+104], %l0
83; SOFT-NEXT: ld [%fp+96], %l1
84; SOFT-NEXT: ld [%fp+100], %l2
85; SOFT-NEXT: ld [%fp+92], %l3
86; SOFT-NEXT:  mov  %i2, %o0
87; SOFT-NEXT: call __extendsfdf2
88; SOFT-NEXT: nop
89; SOFT-NEXT:  mov  %o0, %i2
90; SOFT-NEXT:  mov  %o1, %g2
91; SOFT-NEXT:  mov  %i0, %o0
92; SOFT-NEXT:  mov  %i1, %o1
93; SOFT-NEXT:  mov  %i2, %o2
94; SOFT-NEXT:  mov  %g2, %o3
95; SOFT-NEXT:  call __adddf3
96; SOFT-NEXT:  nop
97; SOFT-NEXT:  mov  %o0, %i0
98; SOFT-NEXT:  mov  %o1, %i1
99; SOFT-NEXT:  mov  %i3, %o0
100; SOFT-NEXT:  mov  %i4, %o1
101; SOFT-NEXT:  mov  %i0, %o2
102; SOFT-NEXT:  mov  %i1, %o3
103; SOFT-NEXT:  call __adddf3
104; SOFT-NEXT:  nop
105; SOFT-NEXT:  mov  %o0, %i0
106; SOFT-NEXT:  mov  %o1, %i1
107; SOFT-NEXT:  mov  %i5, %o0
108; SOFT-NEXT:  mov  %l3, %o1
109; SOFT-NEXT:  mov  %i0, %o2
110; SOFT-NEXT:  mov  %i1, %o3
111; SOFT-NEXT:  call __adddf3
112; SOFT-NEXT:  nop
113; SOFT-NEXT:  mov  %o0, %i0
114; SOFT-NEXT:  mov  %o1, %i1
115; SOFT-NEXT:  mov  %l1, %o0
116; SOFT-NEXT:  mov  %l2, %o1
117; SOFT-NEXT:  mov  %i0, %o2
118; SOFT-NEXT:  mov  %i1, %o3
119; SOFT-NEXT:  call __adddf3
120; SOFT-NEXT:  nop
121; SOFT-NEXT:  mov  %o0, %i0
122; SOFT-NEXT:  mov  %o1, %i1
123; SOFT-NEXT:  mov  %l0, %o0
124; SOFT-NEXT:  call __extendsfdf2
125; SOFT-NEXT:  nop
126; SOFT-NEXT:  mov  %i0, %o2
127; SOFT-NEXT:  mov  %i1, %o3
128; SOFT-NEXT:  call __adddf3
129; SOFT-NEXT:  nop
130; SOFT-NEXT:  mov  %o0, %i0
131; SOFT-NEXT:  mov  %o1, %i1
132; CHECK: restore
133define double @floatarg(double %a0,   ; %i0,%i1
134                        float %a1,    ; %i2
135                        double %a2,   ; %i3, %i4
136                        double %a3,   ; %i5, [%fp+92] (using 4 bytes)
137                        double %a4,   ; [%fp+96] (using 8 bytes)
138                        float %a5) {  ; [%fp+104] (using 4 bytes)
139  %d1 = fpext float %a1 to double
140  %s1 = fadd double %a0, %d1
141  %s2 = fadd double %a2, %s1
142  %s3 = fadd double %a3, %s2
143  %s4 = fadd double %a4, %s3
144  %d5 = fpext float %a5 to double
145  %s5 = fadd double %d5, %s4
146  ret double %s5
147}
148
149; CHECK-LABEL: call_floatarg:
150; HARD: save %sp, -112, %sp
151; HARD: mov %i2, %o1
152; HARD-NEXT: mov %i1, %o0
153; HARD-NEXT: st %i0, [%sp+104]
154; HARD-NEXT: std %o0, [%sp+96]
155; HARD-NEXT: st %o1, [%sp+92]
156; HARD-NEXT: mov %i0, %o2
157; HARD-NEXT: mov %o0, %o3
158; HARD-NEXT: mov %o1, %o4
159; HARD-NEXT: mov %o0, %o5
160; HARD-NEXT: call floatarg
161; HARD: std %f0, [%i4]
162; SOFT: st %i0, [%sp+104]
163; SOFT-NEXT:  st %i2, [%sp+100]
164; SOFT-NEXT:  st %i1, [%sp+96]
165; SOFT-NEXT:  st %i2, [%sp+92]
166; SOFT-NEXT:  mov  %i1, %o0
167; SOFT-NEXT:  mov  %i2, %o1
168; SOFT-NEXT:  mov  %i0, %o2
169; SOFT-NEXT:  mov  %i1, %o3
170; SOFT-NEXT:  mov  %i2, %o4
171; SOFT-NEXT:  mov  %i1, %o5
172; SOFT-NEXT:  call floatarg
173; SOFT:  std %o0, [%i4]
174; CHECK: restore
175define void @call_floatarg(float %f1, double %d2, float %f5, double *%p) {
176  %r = call double @floatarg(double %d2, float %f1, double %d2, double %d2,
177                             double %d2, float %f1)
178  store double %r, double* %p
179  ret void
180}
181
182;; i64 arguments should effectively work the same as double: split
183;; into two locations.  This is different for little-endian vs big
184;; endian, since the 64-bit math needs to be split
185; CHECK-LABEL: i64arg:
186; CHECK:  save %sp, -96, %sp
187; CHECK-BE: ld [%fp+100], %g2
188; CHECK-BE-NEXT: ld [%fp+96], %g3
189; CHECK-BE-NEXT: ld [%fp+92], %g4
190; CHECK-BE-NEXT: addcc %i1, %i2, %i1
191; CHECK-BE-NEXT: addxcc %i0, 0, %i0
192; CHECK-BE-NEXT: addcc %i4, %i1, %i1
193; CHECK-BE-NEXT: addxcc %i3, %i0, %i0
194; CHECK-BE-NEXT: addcc %g4, %i1, %i1
195; CHECK-BE-NEXT: ld [%fp+104], %i2
196; CHECK-BE-NEXT: addxcc %i5, %i0, %i0
197; CHECK-BE-NEXT: addcc %g2, %i1, %i1
198; CHECK-BE-NEXT: addxcc %g3, %i0, %i0
199; CHECK-BE-NEXT: addcc %i2, %i1, %i1
200; CHECK-BE-NEXT: addxcc %i0, 0, %i0
201;
202; CHECK-LE: ld [%fp+96], %g2
203; CHECK-LE-NEXT: ld [%fp+100], %g3
204; CHECK-LE-NEXT: ld [%fp+92], %g4
205; CHECK-LE-NEXT: addcc %i0, %i2, %i0
206; CHECK-LE-NEXT: addxcc %i1, 0, %i1
207; CHECK-LE-NEXT: addcc %i3, %i0, %i0
208; CHECK-LE-NEXT: addxcc %i4, %i1, %i1
209; CHECK-LE-NEXT: addcc %i5, %i0, %i0
210; CHECK-LE-NEXT: ld [%fp+104], %i2
211; CHECK-LE-NEXT: addxcc %g4, %i1, %i1
212; CHECK-LE-NEXT: addcc %g2, %i0, %i0
213; CHECK-LE-NEXT: addxcc %g3, %i1, %i1
214; CHECK-LE-NEXT: addcc %i2, %i0, %i0
215; CHECK-LE-NEXT: addxcc %i1, 0, %i1
216; CHECK-NEXT: restore
217
218
219define i64 @i64arg(i64 %a0,    ; %i0,%i1
220		   i32 %a1,    ; %i2
221		   i64 %a2,    ; %i3, %i4
222		   i64 %a3,    ; %i5, [%fp+92] (using 4 bytes)
223		   i64 %a4,    ; [%fp+96] (using 8 bytes)
224                   i32 %a5) {  ; [%fp+104] (using 4 bytes)
225  %a1L = zext i32 %a1 to i64
226  %s1 = add i64 %a0, %a1L
227  %s2 = add i64 %a2, %s1
228  %s3 = add i64 %a3, %s2
229  %s4 = add i64 %a4, %s3
230  %a5L = zext i32 %a5 to i64
231  %s5 = add i64 %a5L, %s4
232  ret i64 %s5
233}
234
235; CHECK-LABEL: call_i64arg:
236; CHECK: save %sp, -112, %sp
237; CHECK: st %i0, [%sp+104]
238; CHECK-NEXT: st %i2, [%sp+100]
239; CHECK-NEXT: st %i1, [%sp+96]
240; CHECK-NEXT: st %i2, [%sp+92]
241; CHECK-NEXT: mov      %i1, %o0
242; CHECK-NEXT: mov      %i2, %o1
243; CHECK-NEXT: mov      %i0, %o2
244; CHECK-NEXT: mov      %i1, %o3
245; CHECK-NEXT: mov      %i2, %o4
246; CHECK-NEXT: mov      %i1, %o5
247; CHECK-NEXT: call i64arg
248; CHECK: std %o0, [%i3]
249; CHECK-NEXT: restore
250
251define void @call_i64arg(i32 %a0, i64 %a1, i64* %p) {
252  %r = call i64 @i64arg(i64 %a1, i32 %a0, i64 %a1, i64 %a1, i64 %a1, i32 %a0)
253  store i64 %r, i64* %p
254  ret void
255}
256