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
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]
20 define void @intarg(i8 %a0, ; %i0
26 i32 signext %a6, ; [%fp+92]
28 store volatile i8 %a0, ptr %a4
29 store volatile i8 %a1, ptr %a4
30 %p16 = bitcast ptr %a4 to ptr
31 store volatile i16 %a2, ptr %p16
32 %p32 = bitcast ptr %a4 to ptr
33 store volatile i32 %a3, ptr %p32
34 %pp = bitcast ptr %a4 to ptr
35 store volatile ptr %a4, ptr %pp
36 store volatile i32 %a5, ptr %p32
37 store volatile i32 %a6, ptr %p32
38 store volatile ptr %a7, ptr %pp
42 ; CHECK-LABEL: call_intarg:
43 ; CHECK: save %sp, -104, %sp
44 ; Use %o0-%o5 for outgoing arguments
46 ; CHECK: st %i0, [%sp+92]
50 define void @call_intarg(i32 %i0, ptr %i1) {
51 call void @intarg(i8 0, i8 1, i16 2, i32 3, ptr undef, i32 5, i32 %i0, ptr %i1)
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.
58 ; CHECK-LABEL: floatarg:
59 ; HARD: save %sp, -120, %sp
61 ; HARD-NEXT: ld [%fp+92], %g3
62 ; HARD-NEXT: mov %i4, %i5
64 ; HARD-NEXT: std %g2, [%fp+-24]
65 ; HARD-NEXT: mov %i3, %i4
66 ; HARD-NEXT: std %i4, [%fp+-16]
68 ; HARD-NEXT: std %i0, [%fp+-8]
69 ; HARD-NEXT: st %i2, [%fp+-28]
70 ; HARD-NEXT: ld [%fp+104], %f0
71 ; HARD-NEXT: ldd [%fp+96], %f2
72 ; HARD-NEXT: ld [%fp+-28], %f1
73 ; HARD-NEXT: ldd [%fp+-8], %f4
74 ; HARD-NEXT: ldd [%fp+-16], %f6
75 ; HARD-NEXT: ldd [%fp+-24], %f8
76 ; HARD-NEXT: fstod %f1, %f10
77 ; HARD-NEXT: faddd %f4, %f10, %f4
78 ; HARD-NEXT: faddd %f6, %f4, %f4
79 ; HARD-NEXT: faddd %f8, %f4, %f4
80 ; HARD-NEXT: faddd %f2, %f4, %f2
81 ; HARD-NEXT: fstod %f0, %f0
82 ; HARD-NEXT: faddd %f0, %f2, %f0
83 ; SOFT: save %sp, -96, %sp
84 ; SOFT: ld [%fp+104], %l0
85 ; SOFT-NEXT: ld [%fp+96], %l1
86 ; SOFT-NEXT: ld [%fp+100], %l2
87 ; SOFT-NEXT: ld [%fp+92], %l3
88 ; SOFT-NEXT: mov %i2, %o0
89 ; SOFT-NEXT: call __extendsfdf2
91 ; SOFT-NEXT: mov %o0, %o2
92 ; SOFT-NEXT: mov %o1, %o3
93 ; SOFT-NEXT: mov %i0, %o0
94 ; SOFT-NEXT: mov %i1, %o1
95 ; SOFT-NEXT: call __adddf3
97 ; SOFT-NEXT: mov %o0, %o2
98 ; SOFT-NEXT: mov %o1, %o3
99 ; SOFT-NEXT: mov %i3, %o0
100 ; SOFT-NEXT: mov %i4, %o1
101 ; SOFT-NEXT: call __adddf3
103 ; SOFT-NEXT: mov %o0, %o2
104 ; SOFT-NEXT: mov %o1, %o3
105 ; SOFT-NEXT: mov %i5, %o0
106 ; SOFT-NEXT: mov %l3, %o1
107 ; SOFT-NEXT: call __adddf3
109 ; SOFT-NEXT: mov %o0, %o2
110 ; SOFT-NEXT: mov %o1, %o3
111 ; SOFT-NEXT: mov %l1, %o0
112 ; SOFT-NEXT: mov %l2, %o1
113 ; SOFT-NEXT: call __adddf3
115 ; SOFT-NEXT: mov %o0, %i0
116 ; SOFT-NEXT: mov %o1, %i1
117 ; SOFT-NEXT: mov %l0, %o0
118 ; SOFT-NEXT: call __extendsfdf2
120 ; SOFT-NEXT: mov %i0, %o2
121 ; SOFT-NEXT: mov %i1, %o3
122 ; SOFT-NEXT: call __adddf3
124 ; SOFT-NEXT: mov %o0, %i0
125 ; SOFT-NEXT: mov %o1, %i1
127 define double @floatarg(double %a0, ; %i0,%i1
129 double %a2, ; %i3, %i4
130 double %a3, ; %i5, [%fp+92] (using 4 bytes)
131 double %a4, ; [%fp+96] (using 8 bytes)
132 float %a5) { ; [%fp+104] (using 4 bytes)
133 %d1 = fpext float %a1 to double
134 %s1 = fadd double %a0, %d1
135 %s2 = fadd double %a2, %s1
136 %s3 = fadd double %a3, %s2
137 %s4 = fadd double %a4, %s3
138 %d5 = fpext float %a5 to double
139 %s5 = fadd double %d5, %s4
143 ; CHECK-LABEL: call_floatarg:
144 ; HARD: save %sp, -112, %sp
146 ; HARD-NEXT: mov %i1, %o0
147 ; HARD-NEXT: st %i0, [%sp+104]
148 ; HARD-NEXT: std %o0, [%sp+96]
149 ; HARD-NEXT: st %o1, [%sp+92]
150 ; HARD-NEXT: mov %i0, %o2
151 ; HARD-NEXT: mov %i1, %o3
152 ; HARD-NEXT: mov %o1, %o4
153 ; HARD-NEXT: mov %i1, %o5
154 ; HARD-NEXT: call floatarg
155 ; HARD: std %f0, [%i4]
156 ; SOFT: st %i0, [%sp+104]
157 ; SOFT-NEXT: st %i2, [%sp+100]
158 ; SOFT-NEXT: st %i1, [%sp+96]
159 ; SOFT-NEXT: st %i2, [%sp+92]
160 ; SOFT-NEXT: mov %i1, %o0
161 ; SOFT-NEXT: mov %i2, %o1
162 ; SOFT-NEXT: mov %i0, %o2
163 ; SOFT-NEXT: mov %i1, %o3
164 ; SOFT-NEXT: mov %i2, %o4
165 ; SOFT-NEXT: mov %i1, %o5
166 ; SOFT-NEXT: call floatarg
167 ; SOFT: std %o0, [%i4]
169 define void @call_floatarg(float %f1, double %d2, float %f5, ptr %p) {
170 %r = call double @floatarg(double %d2, float %f1, double %d2, double %d2,
171 double %d2, float %f1)
172 store double %r, ptr %p
176 ;; i64 arguments should effectively work the same as double: split
177 ;; into two locations. This is different for little-endian vs big
178 ;; endian, since the 64-bit math needs to be split
179 ; CHECK-LABEL: i64arg:
180 ; CHECK: save %sp, -96, %sp
181 ; CHECK-BE: ld [%fp+104], %g2
182 ; CHECK-BE-NEXT: ld [%fp+100], %g3
183 ; CHECK-BE-NEXT: ld [%fp+96], %g4
184 ; CHECK-BE-NEXT: ld [%fp+92], %l0
185 ; CHECK-BE-NEXT: addcc %i1, %i2, %i1
186 ; CHECK-BE-NEXT: addxcc %i0, 0, %i0
187 ; CHECK-BE-NEXT: addcc %i4, %i1, %i1
188 ; CHECK-BE-NEXT: addxcc %i3, %i0, %i0
189 ; CHECK-BE-NEXT: addcc %l0, %i1, %i1
190 ; CHECK-BE-NEXT: addxcc %i5, %i0, %i0
191 ; CHECK-BE-NEXT: addcc %g3, %i1, %i1
192 ; CHECK-BE-NEXT: addxcc %g4, %i0, %i0
193 ; CHECK-BE-NEXT: addcc %g2, %i1, %i1
194 ; CHECK-BE-NEXT: addxcc %i0, 0, %i0
196 ; CHECK-LE: ld [%fp+104], %g2
197 ; CHECK-LE-NEXT: ld [%fp+96], %g3
198 ; CHECK-LE-NEXT: ld [%fp+100], %g4
199 ; CHECK-LE-NEXT: ld [%fp+92], %l0
200 ; CHECK-LE-NEXT: addcc %i0, %i2, %i0
201 ; CHECK-LE-NEXT: addxcc %i1, 0, %i1
202 ; CHECK-LE-NEXT: addcc %i3, %i0, %i0
203 ; CHECK-LE-NEXT: addxcc %i4, %i1, %i1
204 ; CHECK-LE-NEXT: addcc %i5, %i0, %i0
205 ; CHECK-LE-NEXT: addxcc %l0, %i1, %i1
206 ; CHECK-LE-NEXT: addcc %g3, %i0, %i0
207 ; CHECK-LE-NEXT: addxcc %g4, %i1, %i1
208 ; CHECK-LE-NEXT: addcc %g2, %i0, %i0
209 ; CHECK-LE-NEXT: addxcc %i1, 0, %i1
210 ; CHECK-NEXT: restore
213 define i64 @i64arg(i64 %a0, ; %i0,%i1
216 i64 %a3, ; %i5, [%fp+92] (using 4 bytes)
217 i64 %a4, ; [%fp+96] (using 8 bytes)
218 i32 %a5) { ; [%fp+104] (using 4 bytes)
219 %a1L = zext i32 %a1 to i64
220 %s1 = add i64 %a0, %a1L
221 %s2 = add i64 %a2, %s1
222 %s3 = add i64 %a3, %s2
223 %s4 = add i64 %a4, %s3
224 %a5L = zext i32 %a5 to i64
225 %s5 = add i64 %a5L, %s4
229 ; CHECK-LABEL: call_i64arg:
230 ; CHECK: save %sp, -112, %sp
231 ; CHECK: st %i0, [%sp+104]
232 ; CHECK-NEXT: st %i2, [%sp+100]
233 ; CHECK-NEXT: st %i1, [%sp+96]
234 ; CHECK-NEXT: st %i2, [%sp+92]
235 ; CHECK-NEXT: mov %i1, %o0
236 ; CHECK-NEXT: mov %i2, %o1
237 ; CHECK-NEXT: mov %i0, %o2
238 ; CHECK-NEXT: mov %i1, %o3
239 ; CHECK-NEXT: mov %i2, %o4
240 ; CHECK-NEXT: mov %i1, %o5
241 ; CHECK-NEXT: call i64arg
242 ; CHECK: std %o0, [%i3]
243 ; CHECK-NEXT: restore
245 define void @call_i64arg(i32 %a0, i64 %a1, ptr %p) {
246 %r = call i64 @i64arg(i64 %a1, i32 %a0, i64 %a1, i64 %a1, i64 %a1, i32 %a0)