1 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2 ; RUN: llc -mtriple=riscv32 -mattr=+d -verify-machineinstrs < %s \
3 ; RUN: -target-abi=ilp32d | FileCheck -check-prefixes=CHECKIFD,RV32IFD %s
4 ; RUN: llc -mtriple=riscv64 -mattr=+d -verify-machineinstrs < %s \
5 ; RUN: -target-abi=lp64d | FileCheck -check-prefixes=CHECKIFD,RV64IFD %s
6 ; RUN: llc -mtriple=riscv32 -mattr=+zdinx -verify-machineinstrs < %s \
7 ; RUN: -target-abi=ilp32 | FileCheck -check-prefixes=RV32IZFINXZDINX %s
8 ; RUN: llc -mtriple=riscv64 -mattr=+zdinx -verify-machineinstrs < %s \
9 ; RUN: -target-abi=lp64 | FileCheck -check-prefixes=RV64IZFINXZDINX %s
11 define dso_local double @fld(ptr %a) nounwind {
12 ; CHECKIFD-LABEL: fld:
14 ; CHECKIFD-NEXT: fld fa5, 0(a0)
15 ; CHECKIFD-NEXT: fld fa4, 24(a0)
16 ; CHECKIFD-NEXT: fadd.d fa0, fa5, fa4
19 ; RV32IZFINXZDINX-LABEL: fld:
20 ; RV32IZFINXZDINX: # %bb.0:
21 ; RV32IZFINXZDINX-NEXT: addi sp, sp, -16
22 ; RV32IZFINXZDINX-NEXT: lw a2, 0(a0)
23 ; RV32IZFINXZDINX-NEXT: lw a3, 4(a0)
24 ; RV32IZFINXZDINX-NEXT: lw a1, 28(a0)
25 ; RV32IZFINXZDINX-NEXT: lw a0, 24(a0)
26 ; RV32IZFINXZDINX-NEXT: fadd.d a0, a2, a0
27 ; RV32IZFINXZDINX-NEXT: sw a0, 8(sp)
28 ; RV32IZFINXZDINX-NEXT: sw a1, 12(sp)
29 ; RV32IZFINXZDINX-NEXT: lw a0, 8(sp)
30 ; RV32IZFINXZDINX-NEXT: lw a1, 12(sp)
31 ; RV32IZFINXZDINX-NEXT: addi sp, sp, 16
32 ; RV32IZFINXZDINX-NEXT: ret
34 ; RV64IZFINXZDINX-LABEL: fld:
35 ; RV64IZFINXZDINX: # %bb.0:
36 ; RV64IZFINXZDINX-NEXT: ld a1, 0(a0)
37 ; RV64IZFINXZDINX-NEXT: ld a0, 24(a0)
38 ; RV64IZFINXZDINX-NEXT: fadd.d a0, a1, a0
39 ; RV64IZFINXZDINX-NEXT: ret
40 %1 = load double, ptr %a
41 %2 = getelementptr double, ptr %a, i32 3
42 %3 = load double, ptr %2
43 ; Use both loaded values in an FP op to ensure an fld is used, even for the
45 %4 = fadd double %1, %3
49 define dso_local void @fsd(ptr %a, double %b, double %c) nounwind {
50 ; CHECKIFD-LABEL: fsd:
52 ; CHECKIFD-NEXT: fadd.d fa5, fa0, fa1
53 ; CHECKIFD-NEXT: fsd fa5, 0(a0)
54 ; CHECKIFD-NEXT: fsd fa5, 64(a0)
57 ; RV32IZFINXZDINX-LABEL: fsd:
58 ; RV32IZFINXZDINX: # %bb.0:
59 ; RV32IZFINXZDINX-NEXT: addi sp, sp, -16
60 ; RV32IZFINXZDINX-NEXT: sw a3, 8(sp)
61 ; RV32IZFINXZDINX-NEXT: sw a4, 12(sp)
62 ; RV32IZFINXZDINX-NEXT: lw a4, 8(sp)
63 ; RV32IZFINXZDINX-NEXT: lw a5, 12(sp)
64 ; RV32IZFINXZDINX-NEXT: sw a1, 8(sp)
65 ; RV32IZFINXZDINX-NEXT: sw a2, 12(sp)
66 ; RV32IZFINXZDINX-NEXT: lw a2, 8(sp)
67 ; RV32IZFINXZDINX-NEXT: lw a3, 12(sp)
68 ; RV32IZFINXZDINX-NEXT: fadd.d a2, a2, a4
69 ; RV32IZFINXZDINX-NEXT: sw a2, 0(a0)
70 ; RV32IZFINXZDINX-NEXT: sw a3, 4(a0)
71 ; RV32IZFINXZDINX-NEXT: sw a2, 64(a0)
72 ; RV32IZFINXZDINX-NEXT: sw a3, 68(a0)
73 ; RV32IZFINXZDINX-NEXT: addi sp, sp, 16
74 ; RV32IZFINXZDINX-NEXT: ret
76 ; RV64IZFINXZDINX-LABEL: fsd:
77 ; RV64IZFINXZDINX: # %bb.0:
78 ; RV64IZFINXZDINX-NEXT: fadd.d a1, a1, a2
79 ; RV64IZFINXZDINX-NEXT: sd a1, 0(a0)
80 ; RV64IZFINXZDINX-NEXT: sd a1, 64(a0)
81 ; RV64IZFINXZDINX-NEXT: ret
82 ; Use %b and %c in an FP op to ensure floating point registers are used, even
83 ; for the soft float ABI
84 %1 = fadd double %b, %c
85 store double %1, ptr %a
86 %2 = getelementptr double, ptr %a, i32 8
87 store double %1, ptr %2
91 ; Check load and store to a global
92 @G = dso_local global double 0.0
94 define dso_local double @fld_fsd_global(double %a, double %b) nounwind {
95 ; CHECKIFD-LABEL: fld_fsd_global:
97 ; CHECKIFD-NEXT: fadd.d fa0, fa0, fa1
98 ; CHECKIFD-NEXT: lui a0, %hi(G)
99 ; CHECKIFD-NEXT: fld fa5, %lo(G)(a0)
100 ; CHECKIFD-NEXT: addi a1, a0, %lo(G)
101 ; CHECKIFD-NEXT: fsd fa0, %lo(G)(a0)
102 ; CHECKIFD-NEXT: fld fa5, 72(a1)
103 ; CHECKIFD-NEXT: fsd fa0, 72(a1)
106 ; RV32IZFINXZDINX-LABEL: fld_fsd_global:
107 ; RV32IZFINXZDINX: # %bb.0:
108 ; RV32IZFINXZDINX-NEXT: addi sp, sp, -16
109 ; RV32IZFINXZDINX-NEXT: sw a2, 8(sp)
110 ; RV32IZFINXZDINX-NEXT: sw a3, 12(sp)
111 ; RV32IZFINXZDINX-NEXT: lw a2, 8(sp)
112 ; RV32IZFINXZDINX-NEXT: lw a3, 12(sp)
113 ; RV32IZFINXZDINX-NEXT: sw a0, 8(sp)
114 ; RV32IZFINXZDINX-NEXT: sw a1, 12(sp)
115 ; RV32IZFINXZDINX-NEXT: lw a0, 8(sp)
116 ; RV32IZFINXZDINX-NEXT: lw a1, 12(sp)
117 ; RV32IZFINXZDINX-NEXT: fadd.d a0, a0, a2
118 ; RV32IZFINXZDINX-NEXT: lui a2, %hi(G)
119 ; RV32IZFINXZDINX-NEXT: lw a4, %lo(G)(a2)
120 ; RV32IZFINXZDINX-NEXT: lw a5, %lo(G+4)(a2)
121 ; RV32IZFINXZDINX-NEXT: addi a3, a2, %lo(G)
122 ; RV32IZFINXZDINX-NEXT: sw a0, %lo(G)(a2)
123 ; RV32IZFINXZDINX-NEXT: sw a1, %lo(G+4)(a2)
124 ; RV32IZFINXZDINX-NEXT: lw a4, 72(a3)
125 ; RV32IZFINXZDINX-NEXT: lw a5, 76(a3)
126 ; RV32IZFINXZDINX-NEXT: sw a0, 72(a3)
127 ; RV32IZFINXZDINX-NEXT: sw a1, 76(a3)
128 ; RV32IZFINXZDINX-NEXT: sw a0, 8(sp)
129 ; RV32IZFINXZDINX-NEXT: sw a1, 12(sp)
130 ; RV32IZFINXZDINX-NEXT: lw a0, 8(sp)
131 ; RV32IZFINXZDINX-NEXT: lw a1, 12(sp)
132 ; RV32IZFINXZDINX-NEXT: addi sp, sp, 16
133 ; RV32IZFINXZDINX-NEXT: ret
135 ; RV64IZFINXZDINX-LABEL: fld_fsd_global:
136 ; RV64IZFINXZDINX: # %bb.0:
137 ; RV64IZFINXZDINX-NEXT: fadd.d a0, a0, a1
138 ; RV64IZFINXZDINX-NEXT: lui a1, %hi(G)
139 ; RV64IZFINXZDINX-NEXT: ld zero, %lo(G)(a1)
140 ; RV64IZFINXZDINX-NEXT: addi a2, a1, %lo(G)
141 ; RV64IZFINXZDINX-NEXT: sd a0, %lo(G)(a1)
142 ; RV64IZFINXZDINX-NEXT: ld zero, 72(a2)
143 ; RV64IZFINXZDINX-NEXT: sd a0, 72(a2)
144 ; RV64IZFINXZDINX-NEXT: ret
145 ; Use %a and %b in an FP op to ensure floating point registers are used, even
146 ; for the soft float ABI
147 %1 = fadd double %a, %b
148 %2 = load volatile double, ptr @G
149 store double %1, ptr @G
150 %3 = getelementptr double, ptr @G, i32 9
151 %4 = load volatile double, ptr %3
152 store double %1, ptr %3
156 ; Ensure that 1 is added to the high 20 bits if bit 11 of the low part is 1
157 define dso_local double @fld_fsd_constant(double %a) nounwind {
158 ; RV32IFD-LABEL: fld_fsd_constant:
160 ; RV32IFD-NEXT: lui a0, 912092
161 ; RV32IFD-NEXT: fld fa5, -273(a0)
162 ; RV32IFD-NEXT: fadd.d fa0, fa0, fa5
163 ; RV32IFD-NEXT: fsd fa0, -273(a0)
166 ; RV64IFD-LABEL: fld_fsd_constant:
168 ; RV64IFD-NEXT: lui a0, 228023
169 ; RV64IFD-NEXT: slli a0, a0, 2
170 ; RV64IFD-NEXT: fld fa5, -273(a0)
171 ; RV64IFD-NEXT: fadd.d fa0, fa0, fa5
172 ; RV64IFD-NEXT: fsd fa0, -273(a0)
175 ; RV32IZFINXZDINX-LABEL: fld_fsd_constant:
176 ; RV32IZFINXZDINX: # %bb.0:
177 ; RV32IZFINXZDINX-NEXT: addi sp, sp, -16
178 ; RV32IZFINXZDINX-NEXT: sw a0, 8(sp)
179 ; RV32IZFINXZDINX-NEXT: sw a1, 12(sp)
180 ; RV32IZFINXZDINX-NEXT: lw a0, 8(sp)
181 ; RV32IZFINXZDINX-NEXT: lw a1, 12(sp)
182 ; RV32IZFINXZDINX-NEXT: lui a2, 912092
183 ; RV32IZFINXZDINX-NEXT: lw a4, -273(a2)
184 ; RV32IZFINXZDINX-NEXT: lw a5, -269(a2)
185 ; RV32IZFINXZDINX-NEXT: fadd.d a0, a0, a4
186 ; RV32IZFINXZDINX-NEXT: sw a0, -273(a2)
187 ; RV32IZFINXZDINX-NEXT: sw a1, -269(a2)
188 ; RV32IZFINXZDINX-NEXT: sw a0, 8(sp)
189 ; RV32IZFINXZDINX-NEXT: sw a1, 12(sp)
190 ; RV32IZFINXZDINX-NEXT: lw a0, 8(sp)
191 ; RV32IZFINXZDINX-NEXT: lw a1, 12(sp)
192 ; RV32IZFINXZDINX-NEXT: addi sp, sp, 16
193 ; RV32IZFINXZDINX-NEXT: ret
195 ; RV64IZFINXZDINX-LABEL: fld_fsd_constant:
196 ; RV64IZFINXZDINX: # %bb.0:
197 ; RV64IZFINXZDINX-NEXT: lui a1, 228023
198 ; RV64IZFINXZDINX-NEXT: slli a1, a1, 2
199 ; RV64IZFINXZDINX-NEXT: ld a2, -273(a1)
200 ; RV64IZFINXZDINX-NEXT: fadd.d a0, a0, a2
201 ; RV64IZFINXZDINX-NEXT: sd a0, -273(a1)
202 ; RV64IZFINXZDINX-NEXT: ret
203 %1 = inttoptr i32 3735928559 to ptr
204 %2 = load volatile double, ptr %1
205 %3 = fadd double %a, %2
206 store double %3, ptr %1
210 declare void @notdead(ptr)
212 define dso_local double @fld_stack(double %a) nounwind {
213 ; RV32IFD-LABEL: fld_stack:
215 ; RV32IFD-NEXT: addi sp, sp, -32
216 ; RV32IFD-NEXT: sw ra, 28(sp) # 4-byte Folded Spill
217 ; RV32IFD-NEXT: fsd fs0, 16(sp) # 8-byte Folded Spill
218 ; RV32IFD-NEXT: fmv.d fs0, fa0
219 ; RV32IFD-NEXT: addi a0, sp, 8
220 ; RV32IFD-NEXT: call notdead
221 ; RV32IFD-NEXT: fld fa5, 8(sp)
222 ; RV32IFD-NEXT: fadd.d fa0, fa5, fs0
223 ; RV32IFD-NEXT: lw ra, 28(sp) # 4-byte Folded Reload
224 ; RV32IFD-NEXT: fld fs0, 16(sp) # 8-byte Folded Reload
225 ; RV32IFD-NEXT: addi sp, sp, 32
228 ; RV64IFD-LABEL: fld_stack:
230 ; RV64IFD-NEXT: addi sp, sp, -32
231 ; RV64IFD-NEXT: sd ra, 24(sp) # 8-byte Folded Spill
232 ; RV64IFD-NEXT: fsd fs0, 16(sp) # 8-byte Folded Spill
233 ; RV64IFD-NEXT: fmv.d fs0, fa0
234 ; RV64IFD-NEXT: addi a0, sp, 8
235 ; RV64IFD-NEXT: call notdead
236 ; RV64IFD-NEXT: fld fa5, 8(sp)
237 ; RV64IFD-NEXT: fadd.d fa0, fa5, fs0
238 ; RV64IFD-NEXT: ld ra, 24(sp) # 8-byte Folded Reload
239 ; RV64IFD-NEXT: fld fs0, 16(sp) # 8-byte Folded Reload
240 ; RV64IFD-NEXT: addi sp, sp, 32
243 ; RV32IZFINXZDINX-LABEL: fld_stack:
244 ; RV32IZFINXZDINX: # %bb.0:
245 ; RV32IZFINXZDINX-NEXT: addi sp, sp, -32
246 ; RV32IZFINXZDINX-NEXT: sw ra, 28(sp) # 4-byte Folded Spill
247 ; RV32IZFINXZDINX-NEXT: sw s0, 24(sp) # 4-byte Folded Spill
248 ; RV32IZFINXZDINX-NEXT: sw s1, 20(sp) # 4-byte Folded Spill
249 ; RV32IZFINXZDINX-NEXT: sw a0, 0(sp)
250 ; RV32IZFINXZDINX-NEXT: sw a1, 4(sp)
251 ; RV32IZFINXZDINX-NEXT: lw s0, 0(sp)
252 ; RV32IZFINXZDINX-NEXT: lw s1, 4(sp)
253 ; RV32IZFINXZDINX-NEXT: addi a0, sp, 8
254 ; RV32IZFINXZDINX-NEXT: call notdead
255 ; RV32IZFINXZDINX-NEXT: lw a0, 8(sp)
256 ; RV32IZFINXZDINX-NEXT: lw a1, 12(sp)
257 ; RV32IZFINXZDINX-NEXT: fadd.d a0, a0, s0
258 ; RV32IZFINXZDINX-NEXT: sw a0, 0(sp)
259 ; RV32IZFINXZDINX-NEXT: sw a1, 4(sp)
260 ; RV32IZFINXZDINX-NEXT: lw a0, 0(sp)
261 ; RV32IZFINXZDINX-NEXT: lw a1, 4(sp)
262 ; RV32IZFINXZDINX-NEXT: lw ra, 28(sp) # 4-byte Folded Reload
263 ; RV32IZFINXZDINX-NEXT: lw s0, 24(sp) # 4-byte Folded Reload
264 ; RV32IZFINXZDINX-NEXT: lw s1, 20(sp) # 4-byte Folded Reload
265 ; RV32IZFINXZDINX-NEXT: addi sp, sp, 32
266 ; RV32IZFINXZDINX-NEXT: ret
268 ; RV64IZFINXZDINX-LABEL: fld_stack:
269 ; RV64IZFINXZDINX: # %bb.0:
270 ; RV64IZFINXZDINX-NEXT: addi sp, sp, -32
271 ; RV64IZFINXZDINX-NEXT: sd ra, 24(sp) # 8-byte Folded Spill
272 ; RV64IZFINXZDINX-NEXT: sd s0, 16(sp) # 8-byte Folded Spill
273 ; RV64IZFINXZDINX-NEXT: mv s0, a0
274 ; RV64IZFINXZDINX-NEXT: addi a0, sp, 8
275 ; RV64IZFINXZDINX-NEXT: call notdead
276 ; RV64IZFINXZDINX-NEXT: ld a0, 8(sp)
277 ; RV64IZFINXZDINX-NEXT: fadd.d a0, a0, s0
278 ; RV64IZFINXZDINX-NEXT: ld ra, 24(sp) # 8-byte Folded Reload
279 ; RV64IZFINXZDINX-NEXT: ld s0, 16(sp) # 8-byte Folded Reload
280 ; RV64IZFINXZDINX-NEXT: addi sp, sp, 32
281 ; RV64IZFINXZDINX-NEXT: ret
282 %1 = alloca double, align 8
283 call void @notdead(ptr %1)
284 %2 = load double, ptr %1
285 %3 = fadd double %2, %a ; force load in to FPR64
289 define dso_local void @fsd_stack(double %a, double %b) nounwind {
290 ; RV32IFD-LABEL: fsd_stack:
292 ; RV32IFD-NEXT: addi sp, sp, -16
293 ; RV32IFD-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
294 ; RV32IFD-NEXT: fadd.d fa5, fa0, fa1
295 ; RV32IFD-NEXT: fsd fa5, 0(sp)
296 ; RV32IFD-NEXT: mv a0, sp
297 ; RV32IFD-NEXT: call notdead
298 ; RV32IFD-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
299 ; RV32IFD-NEXT: addi sp, sp, 16
302 ; RV64IFD-LABEL: fsd_stack:
304 ; RV64IFD-NEXT: addi sp, sp, -16
305 ; RV64IFD-NEXT: sd ra, 8(sp) # 8-byte Folded Spill
306 ; RV64IFD-NEXT: fadd.d fa5, fa0, fa1
307 ; RV64IFD-NEXT: fsd fa5, 0(sp)
308 ; RV64IFD-NEXT: mv a0, sp
309 ; RV64IFD-NEXT: call notdead
310 ; RV64IFD-NEXT: ld ra, 8(sp) # 8-byte Folded Reload
311 ; RV64IFD-NEXT: addi sp, sp, 16
314 ; RV32IZFINXZDINX-LABEL: fsd_stack:
315 ; RV32IZFINXZDINX: # %bb.0:
316 ; RV32IZFINXZDINX-NEXT: addi sp, sp, -32
317 ; RV32IZFINXZDINX-NEXT: sw ra, 28(sp) # 4-byte Folded Spill
318 ; RV32IZFINXZDINX-NEXT: sw a2, 8(sp)
319 ; RV32IZFINXZDINX-NEXT: sw a3, 12(sp)
320 ; RV32IZFINXZDINX-NEXT: lw a2, 8(sp)
321 ; RV32IZFINXZDINX-NEXT: lw a3, 12(sp)
322 ; RV32IZFINXZDINX-NEXT: sw a0, 8(sp)
323 ; RV32IZFINXZDINX-NEXT: sw a1, 12(sp)
324 ; RV32IZFINXZDINX-NEXT: lw a0, 8(sp)
325 ; RV32IZFINXZDINX-NEXT: lw a1, 12(sp)
326 ; RV32IZFINXZDINX-NEXT: fadd.d a0, a0, a2
327 ; RV32IZFINXZDINX-NEXT: sw a0, 16(sp)
328 ; RV32IZFINXZDINX-NEXT: sw a1, 20(sp)
329 ; RV32IZFINXZDINX-NEXT: addi a0, sp, 16
330 ; RV32IZFINXZDINX-NEXT: call notdead
331 ; RV32IZFINXZDINX-NEXT: lw ra, 28(sp) # 4-byte Folded Reload
332 ; RV32IZFINXZDINX-NEXT: addi sp, sp, 32
333 ; RV32IZFINXZDINX-NEXT: ret
335 ; RV64IZFINXZDINX-LABEL: fsd_stack:
336 ; RV64IZFINXZDINX: # %bb.0:
337 ; RV64IZFINXZDINX-NEXT: addi sp, sp, -16
338 ; RV64IZFINXZDINX-NEXT: sd ra, 8(sp) # 8-byte Folded Spill
339 ; RV64IZFINXZDINX-NEXT: fadd.d a0, a0, a1
340 ; RV64IZFINXZDINX-NEXT: sd a0, 0(sp)
341 ; RV64IZFINXZDINX-NEXT: mv a0, sp
342 ; RV64IZFINXZDINX-NEXT: call notdead
343 ; RV64IZFINXZDINX-NEXT: ld ra, 8(sp) # 8-byte Folded Reload
344 ; RV64IZFINXZDINX-NEXT: addi sp, sp, 16
345 ; RV64IZFINXZDINX-NEXT: ret
346 %1 = fadd double %a, %b ; force store from FPR64
347 %2 = alloca double, align 8
348 store double %1, ptr %2
349 call void @notdead(ptr %2)
353 ; Test selection of store<ST4[%a], trunc to f32>, ..
354 define dso_local void @fsd_trunc(ptr %a, double %b) nounwind noinline optnone {
355 ; CHECKIFD-LABEL: fsd_trunc:
357 ; CHECKIFD-NEXT: fcvt.s.d fa5, fa0
358 ; CHECKIFD-NEXT: fsw fa5, 0(a0)
361 ; RV32IZFINXZDINX-LABEL: fsd_trunc:
362 ; RV32IZFINXZDINX: # %bb.0:
363 ; RV32IZFINXZDINX-NEXT: addi sp, sp, -16
364 ; RV32IZFINXZDINX-NEXT: sw a1, 8(sp)
365 ; RV32IZFINXZDINX-NEXT: sw a2, 12(sp)
366 ; RV32IZFINXZDINX-NEXT: lw a2, 8(sp)
367 ; RV32IZFINXZDINX-NEXT: lw a3, 12(sp)
368 ; RV32IZFINXZDINX-NEXT: fcvt.s.d a1, a2
369 ; RV32IZFINXZDINX-NEXT: sw a1, 0(a0)
370 ; RV32IZFINXZDINX-NEXT: addi sp, sp, 16
371 ; RV32IZFINXZDINX-NEXT: ret
373 ; RV64IZFINXZDINX-LABEL: fsd_trunc:
374 ; RV64IZFINXZDINX: # %bb.0:
375 ; RV64IZFINXZDINX-NEXT: fcvt.s.d a1, a1
376 ; RV64IZFINXZDINX-NEXT: sw a1, 0(a0)
377 ; RV64IZFINXZDINX-NEXT: ret
378 %1 = fptrunc double %b to float
379 store float %1, ptr %a, align 4