1 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2 ; RUN: llc -mtriple=riscv32 -mattr=+f -verify-machineinstrs < %s \
3 ; RUN: | FileCheck -check-prefix=RV32IF %s
4 ; RUN: llc -mtriple=riscv64 -mattr=+f -verify-machineinstrs < %s \
5 ; RUN: | FileCheck -check-prefix=RV64IF %s
7 ; For RV64F, fcvt.l.s is semantically equivalent to fcvt.w.s in this case
8 ; because fptosi will produce poison if the result doesn't fit into an i32.
9 define i32 @fcvt_w_s(float %a) nounwind {
10 ; RV32IF-LABEL: fcvt_w_s:
12 ; RV32IF-NEXT: fmv.w.x ft0, a0
13 ; RV32IF-NEXT: fcvt.w.s a0, ft0, rtz
16 ; RV64IF-LABEL: fcvt_w_s:
18 ; RV64IF-NEXT: fmv.w.x ft0, a0
19 ; RV64IF-NEXT: fcvt.w.s a0, ft0, rtz
21 %1 = fptosi float %a to i32
25 define i32 @fcvt_w_s_sat(float %a) nounwind {
26 ; RV32IF-LABEL: fcvt_w_s_sat:
27 ; RV32IF: # %bb.0: # %start
28 ; RV32IF-NEXT: fmv.w.x ft0, a0
29 ; RV32IF-NEXT: feq.s a0, ft0, ft0
30 ; RV32IF-NEXT: bnez a0, .LBB1_2
31 ; RV32IF-NEXT: # %bb.1: # %start
32 ; RV32IF-NEXT: mv a0, zero
34 ; RV32IF-NEXT: .LBB1_2:
35 ; RV32IF-NEXT: fcvt.w.s a0, ft0, rtz
38 ; RV64IF-LABEL: fcvt_w_s_sat:
39 ; RV64IF: # %bb.0: # %start
40 ; RV64IF-NEXT: fmv.w.x ft0, a0
41 ; RV64IF-NEXT: feq.s a0, ft0, ft0
42 ; RV64IF-NEXT: bnez a0, .LBB1_2
43 ; RV64IF-NEXT: # %bb.1: # %start
44 ; RV64IF-NEXT: mv a0, zero
46 ; RV64IF-NEXT: .LBB1_2:
47 ; RV64IF-NEXT: fcvt.w.s a0, ft0, rtz
50 %0 = tail call i32 @llvm.fptosi.sat.i32.f32(float %a)
53 declare i32 @llvm.fptosi.sat.i32.f32(float)
55 ; For RV64F, fcvt.lu.s is semantically equivalent to fcvt.wu.s in this case
56 ; because fptoui will produce poison if the result doesn't fit into an i32.
57 define i32 @fcvt_wu_s(float %a) nounwind {
58 ; RV32IF-LABEL: fcvt_wu_s:
60 ; RV32IF-NEXT: fmv.w.x ft0, a0
61 ; RV32IF-NEXT: fcvt.wu.s a0, ft0, rtz
64 ; RV64IF-LABEL: fcvt_wu_s:
66 ; RV64IF-NEXT: fmv.w.x ft0, a0
67 ; RV64IF-NEXT: fcvt.wu.s a0, ft0, rtz
69 %1 = fptoui float %a to i32
73 ; Test where the fptoui has multiple uses, one of which causes a sext to be
75 ; FIXME: We should not have an fcvt.wu.s and an fcvt.lu.s.
76 define i32 @fcvt_wu_s_multiple_use(float %x, i32* %y) {
77 ; RV32IF-LABEL: fcvt_wu_s_multiple_use:
79 ; RV32IF-NEXT: fmv.w.x ft0, a0
80 ; RV32IF-NEXT: fcvt.wu.s a1, ft0, rtz
81 ; RV32IF-NEXT: addi a0, zero, 1
82 ; RV32IF-NEXT: beqz a1, .LBB3_2
83 ; RV32IF-NEXT: # %bb.1:
84 ; RV32IF-NEXT: mv a0, a1
85 ; RV32IF-NEXT: .LBB3_2:
88 ; RV64IF-LABEL: fcvt_wu_s_multiple_use:
90 ; RV64IF-NEXT: fmv.w.x ft0, a0
91 ; RV64IF-NEXT: fcvt.wu.s a1, ft0, rtz
92 ; RV64IF-NEXT: addi a0, zero, 1
93 ; RV64IF-NEXT: beqz a1, .LBB3_2
94 ; RV64IF-NEXT: # %bb.1:
95 ; RV64IF-NEXT: mv a0, a1
96 ; RV64IF-NEXT: .LBB3_2:
98 %a = fptoui float %x to i32
99 %b = icmp eq i32 %a, 0
100 %c = select i1 %b, i32 1, i32 %a
104 define i32 @fcvt_wu_s_sat(float %a) nounwind {
105 ; RV32IF-LABEL: fcvt_wu_s_sat:
106 ; RV32IF: # %bb.0: # %start
107 ; RV32IF-NEXT: fmv.w.x ft0, a0
108 ; RV32IF-NEXT: feq.s a0, ft0, ft0
109 ; RV32IF-NEXT: bnez a0, .LBB4_2
110 ; RV32IF-NEXT: # %bb.1: # %start
111 ; RV32IF-NEXT: mv a0, zero
113 ; RV32IF-NEXT: .LBB4_2:
114 ; RV32IF-NEXT: fcvt.wu.s a0, ft0, rtz
117 ; RV64IF-LABEL: fcvt_wu_s_sat:
118 ; RV64IF: # %bb.0: # %start
119 ; RV64IF-NEXT: fmv.w.x ft0, a0
120 ; RV64IF-NEXT: feq.s a0, ft0, ft0
121 ; RV64IF-NEXT: bnez a0, .LBB4_2
122 ; RV64IF-NEXT: # %bb.1: # %start
123 ; RV64IF-NEXT: mv a0, zero
125 ; RV64IF-NEXT: .LBB4_2:
126 ; RV64IF-NEXT: fcvt.wu.s a0, ft0, rtz
129 %0 = tail call i32 @llvm.fptoui.sat.i32.f32(float %a)
132 declare i32 @llvm.fptoui.sat.i32.f32(float)
134 define i32 @fmv_x_w(float %a, float %b) nounwind {
135 ; RV32IF-LABEL: fmv_x_w:
137 ; RV32IF-NEXT: fmv.w.x ft0, a1
138 ; RV32IF-NEXT: fmv.w.x ft1, a0
139 ; RV32IF-NEXT: fadd.s ft0, ft1, ft0
140 ; RV32IF-NEXT: fmv.x.w a0, ft0
143 ; RV64IF-LABEL: fmv_x_w:
145 ; RV64IF-NEXT: fmv.w.x ft0, a1
146 ; RV64IF-NEXT: fmv.w.x ft1, a0
147 ; RV64IF-NEXT: fadd.s ft0, ft1, ft0
148 ; RV64IF-NEXT: fmv.x.w a0, ft0
150 ; Ensure fmv.x.w is generated even for a soft float calling convention
151 %1 = fadd float %a, %b
152 %2 = bitcast float %1 to i32
156 define float @fcvt_s_w(i32 %a) nounwind {
157 ; RV32IF-LABEL: fcvt_s_w:
159 ; RV32IF-NEXT: fcvt.s.w ft0, a0
160 ; RV32IF-NEXT: fmv.x.w a0, ft0
163 ; RV64IF-LABEL: fcvt_s_w:
165 ; RV64IF-NEXT: fcvt.s.w ft0, a0
166 ; RV64IF-NEXT: fmv.x.w a0, ft0
168 %1 = sitofp i32 %a to float
172 define float @fcvt_s_w_load(i32* %p) nounwind {
173 ; RV32IF-LABEL: fcvt_s_w_load:
175 ; RV32IF-NEXT: lw a0, 0(a0)
176 ; RV32IF-NEXT: fcvt.s.w ft0, a0
177 ; RV32IF-NEXT: fmv.x.w a0, ft0
180 ; RV64IF-LABEL: fcvt_s_w_load:
182 ; RV64IF-NEXT: lw a0, 0(a0)
183 ; RV64IF-NEXT: fcvt.s.w ft0, a0
184 ; RV64IF-NEXT: fmv.x.w a0, ft0
186 %a = load i32, i32* %p
187 %1 = sitofp i32 %a to float
191 define float @fcvt_s_wu(i32 %a) nounwind {
192 ; RV32IF-LABEL: fcvt_s_wu:
194 ; RV32IF-NEXT: fcvt.s.wu ft0, a0
195 ; RV32IF-NEXT: fmv.x.w a0, ft0
198 ; RV64IF-LABEL: fcvt_s_wu:
200 ; RV64IF-NEXT: fcvt.s.wu ft0, a0
201 ; RV64IF-NEXT: fmv.x.w a0, ft0
203 %1 = uitofp i32 %a to float
207 define float @fcvt_s_wu_load(i32* %p) nounwind {
208 ; RV32IF-LABEL: fcvt_s_wu_load:
210 ; RV32IF-NEXT: lw a0, 0(a0)
211 ; RV32IF-NEXT: fcvt.s.wu ft0, a0
212 ; RV32IF-NEXT: fmv.x.w a0, ft0
215 ; RV64IF-LABEL: fcvt_s_wu_load:
217 ; RV64IF-NEXT: lwu a0, 0(a0)
218 ; RV64IF-NEXT: fcvt.s.wu ft0, a0
219 ; RV64IF-NEXT: fmv.x.w a0, ft0
221 %a = load i32, i32* %p
222 %1 = uitofp i32 %a to float
226 define float @fmv_w_x(i32 %a, i32 %b) nounwind {
227 ; RV32IF-LABEL: fmv_w_x:
229 ; RV32IF-NEXT: fmv.w.x ft0, a0
230 ; RV32IF-NEXT: fmv.w.x ft1, a1
231 ; RV32IF-NEXT: fadd.s ft0, ft0, ft1
232 ; RV32IF-NEXT: fmv.x.w a0, ft0
235 ; RV64IF-LABEL: fmv_w_x:
237 ; RV64IF-NEXT: fmv.w.x ft0, a0
238 ; RV64IF-NEXT: fmv.w.x ft1, a1
239 ; RV64IF-NEXT: fadd.s ft0, ft0, ft1
240 ; RV64IF-NEXT: fmv.x.w a0, ft0
242 ; Ensure fmv.w.x is generated even for a soft float calling convention
243 %1 = bitcast i32 %a to float
244 %2 = bitcast i32 %b to float
245 %3 = fadd float %1, %2
249 define i64 @fcvt_l_s(float %a) nounwind {
250 ; RV32IF-LABEL: fcvt_l_s:
252 ; RV32IF-NEXT: addi sp, sp, -16
253 ; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
254 ; RV32IF-NEXT: call __fixsfdi@plt
255 ; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
256 ; RV32IF-NEXT: addi sp, sp, 16
259 ; RV64IF-LABEL: fcvt_l_s:
261 ; RV64IF-NEXT: fmv.w.x ft0, a0
262 ; RV64IF-NEXT: fcvt.l.s a0, ft0, rtz
264 %1 = fptosi float %a to i64
268 define i64 @fcvt_l_s_sat(float %a) nounwind {
269 ; RV32IF-LABEL: fcvt_l_s_sat:
270 ; RV32IF: # %bb.0: # %start
271 ; RV32IF-NEXT: addi sp, sp, -16
272 ; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
273 ; RV32IF-NEXT: sw s0, 8(sp) # 4-byte Folded Spill
274 ; RV32IF-NEXT: lui a1, %hi(.LCPI12_0)
275 ; RV32IF-NEXT: flw ft0, %lo(.LCPI12_0)(a1)
276 ; RV32IF-NEXT: fmv.w.x ft1, a0
277 ; RV32IF-NEXT: fsw ft1, 4(sp) # 4-byte Folded Spill
278 ; RV32IF-NEXT: fle.s s0, ft0, ft1
279 ; RV32IF-NEXT: call __fixsfdi@plt
280 ; RV32IF-NEXT: mv a2, a0
281 ; RV32IF-NEXT: bnez s0, .LBB12_2
282 ; RV32IF-NEXT: # %bb.1: # %start
283 ; RV32IF-NEXT: mv a2, zero
284 ; RV32IF-NEXT: .LBB12_2: # %start
285 ; RV32IF-NEXT: lui a0, %hi(.LCPI12_1)
286 ; RV32IF-NEXT: flw ft0, %lo(.LCPI12_1)(a0)
287 ; RV32IF-NEXT: flw ft1, 4(sp) # 4-byte Folded Reload
288 ; RV32IF-NEXT: flt.s a3, ft0, ft1
289 ; RV32IF-NEXT: fmv.s ft0, ft1
290 ; RV32IF-NEXT: addi a0, zero, -1
291 ; RV32IF-NEXT: beqz a3, .LBB12_9
292 ; RV32IF-NEXT: # %bb.3: # %start
293 ; RV32IF-NEXT: feq.s a2, ft0, ft0
294 ; RV32IF-NEXT: beqz a2, .LBB12_10
295 ; RV32IF-NEXT: .LBB12_4: # %start
296 ; RV32IF-NEXT: lui a4, 524288
297 ; RV32IF-NEXT: beqz s0, .LBB12_11
298 ; RV32IF-NEXT: .LBB12_5: # %start
299 ; RV32IF-NEXT: bnez a3, .LBB12_12
300 ; RV32IF-NEXT: .LBB12_6: # %start
301 ; RV32IF-NEXT: bnez a2, .LBB12_8
302 ; RV32IF-NEXT: .LBB12_7: # %start
303 ; RV32IF-NEXT: mv a1, zero
304 ; RV32IF-NEXT: .LBB12_8: # %start
305 ; RV32IF-NEXT: lw s0, 8(sp) # 4-byte Folded Reload
306 ; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
307 ; RV32IF-NEXT: addi sp, sp, 16
309 ; RV32IF-NEXT: .LBB12_9: # %start
310 ; RV32IF-NEXT: mv a0, a2
311 ; RV32IF-NEXT: feq.s a2, ft0, ft0
312 ; RV32IF-NEXT: bnez a2, .LBB12_4
313 ; RV32IF-NEXT: .LBB12_10: # %start
314 ; RV32IF-NEXT: mv a0, zero
315 ; RV32IF-NEXT: lui a4, 524288
316 ; RV32IF-NEXT: bnez s0, .LBB12_5
317 ; RV32IF-NEXT: .LBB12_11: # %start
318 ; RV32IF-NEXT: lui a1, 524288
319 ; RV32IF-NEXT: beqz a3, .LBB12_6
320 ; RV32IF-NEXT: .LBB12_12:
321 ; RV32IF-NEXT: addi a1, a4, -1
322 ; RV32IF-NEXT: beqz a2, .LBB12_7
323 ; RV32IF-NEXT: j .LBB12_8
325 ; RV64IF-LABEL: fcvt_l_s_sat:
326 ; RV64IF: # %bb.0: # %start
327 ; RV64IF-NEXT: fmv.w.x ft0, a0
328 ; RV64IF-NEXT: feq.s a0, ft0, ft0
329 ; RV64IF-NEXT: bnez a0, .LBB12_2
330 ; RV64IF-NEXT: # %bb.1: # %start
331 ; RV64IF-NEXT: mv a0, zero
333 ; RV64IF-NEXT: .LBB12_2:
334 ; RV64IF-NEXT: fcvt.l.s a0, ft0, rtz
337 %0 = tail call i64 @llvm.fptosi.sat.i64.f32(float %a)
340 declare i64 @llvm.fptosi.sat.i64.f32(float)
342 define i64 @fcvt_lu_s(float %a) nounwind {
343 ; RV32IF-LABEL: fcvt_lu_s:
345 ; RV32IF-NEXT: addi sp, sp, -16
346 ; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
347 ; RV32IF-NEXT: call __fixunssfdi@plt
348 ; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
349 ; RV32IF-NEXT: addi sp, sp, 16
352 ; RV64IF-LABEL: fcvt_lu_s:
354 ; RV64IF-NEXT: fmv.w.x ft0, a0
355 ; RV64IF-NEXT: fcvt.lu.s a0, ft0, rtz
357 %1 = fptoui float %a to i64
361 define i64 @fcvt_lu_s_sat(float %a) nounwind {
362 ; RV32IF-LABEL: fcvt_lu_s_sat:
363 ; RV32IF: # %bb.0: # %start
364 ; RV32IF-NEXT: addi sp, sp, -16
365 ; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
366 ; RV32IF-NEXT: sw s0, 8(sp) # 4-byte Folded Spill
367 ; RV32IF-NEXT: fmv.w.x ft1, a0
368 ; RV32IF-NEXT: fmv.w.x ft0, zero
369 ; RV32IF-NEXT: fsw ft1, 4(sp) # 4-byte Folded Spill
370 ; RV32IF-NEXT: fle.s s0, ft0, ft1
371 ; RV32IF-NEXT: call __fixunssfdi@plt
372 ; RV32IF-NEXT: mv a3, a0
373 ; RV32IF-NEXT: bnez s0, .LBB14_2
374 ; RV32IF-NEXT: # %bb.1: # %start
375 ; RV32IF-NEXT: mv a3, zero
376 ; RV32IF-NEXT: .LBB14_2: # %start
377 ; RV32IF-NEXT: lui a0, %hi(.LCPI14_0)
378 ; RV32IF-NEXT: flw ft0, %lo(.LCPI14_0)(a0)
379 ; RV32IF-NEXT: flw ft1, 4(sp) # 4-byte Folded Reload
380 ; RV32IF-NEXT: flt.s a4, ft0, ft1
381 ; RV32IF-NEXT: addi a2, zero, -1
382 ; RV32IF-NEXT: addi a0, zero, -1
383 ; RV32IF-NEXT: beqz a4, .LBB14_7
384 ; RV32IF-NEXT: # %bb.3: # %start
385 ; RV32IF-NEXT: beqz s0, .LBB14_8
386 ; RV32IF-NEXT: .LBB14_4: # %start
387 ; RV32IF-NEXT: bnez a4, .LBB14_6
388 ; RV32IF-NEXT: .LBB14_5: # %start
389 ; RV32IF-NEXT: mv a2, a1
390 ; RV32IF-NEXT: .LBB14_6: # %start
391 ; RV32IF-NEXT: mv a1, a2
392 ; RV32IF-NEXT: lw s0, 8(sp) # 4-byte Folded Reload
393 ; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
394 ; RV32IF-NEXT: addi sp, sp, 16
396 ; RV32IF-NEXT: .LBB14_7: # %start
397 ; RV32IF-NEXT: mv a0, a3
398 ; RV32IF-NEXT: bnez s0, .LBB14_4
399 ; RV32IF-NEXT: .LBB14_8: # %start
400 ; RV32IF-NEXT: mv a1, zero
401 ; RV32IF-NEXT: beqz a4, .LBB14_5
402 ; RV32IF-NEXT: j .LBB14_6
404 ; RV64IF-LABEL: fcvt_lu_s_sat:
405 ; RV64IF: # %bb.0: # %start
406 ; RV64IF-NEXT: fmv.w.x ft0, a0
407 ; RV64IF-NEXT: feq.s a0, ft0, ft0
408 ; RV64IF-NEXT: bnez a0, .LBB14_2
409 ; RV64IF-NEXT: # %bb.1: # %start
410 ; RV64IF-NEXT: mv a0, zero
412 ; RV64IF-NEXT: .LBB14_2:
413 ; RV64IF-NEXT: fcvt.lu.s a0, ft0, rtz
416 %0 = tail call i64 @llvm.fptoui.sat.i64.f32(float %a)
419 declare i64 @llvm.fptoui.sat.i64.f32(float)
421 define float @fcvt_s_l(i64 %a) nounwind {
422 ; RV32IF-LABEL: fcvt_s_l:
424 ; RV32IF-NEXT: addi sp, sp, -16
425 ; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
426 ; RV32IF-NEXT: call __floatdisf@plt
427 ; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
428 ; RV32IF-NEXT: addi sp, sp, 16
431 ; RV64IF-LABEL: fcvt_s_l:
433 ; RV64IF-NEXT: fcvt.s.l ft0, a0
434 ; RV64IF-NEXT: fmv.x.w a0, ft0
436 %1 = sitofp i64 %a to float
440 define float @fcvt_s_lu(i64 %a) nounwind {
441 ; RV32IF-LABEL: fcvt_s_lu:
443 ; RV32IF-NEXT: addi sp, sp, -16
444 ; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
445 ; RV32IF-NEXT: call __floatundisf@plt
446 ; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
447 ; RV32IF-NEXT: addi sp, sp, 16
450 ; RV64IF-LABEL: fcvt_s_lu:
452 ; RV64IF-NEXT: fcvt.s.lu ft0, a0
453 ; RV64IF-NEXT: fmv.x.w a0, ft0
455 %1 = uitofp i64 %a to float
459 define float @fcvt_s_w_i8(i8 signext %a) nounwind {
460 ; RV32IF-LABEL: fcvt_s_w_i8:
462 ; RV32IF-NEXT: fcvt.s.w ft0, a0
463 ; RV32IF-NEXT: fmv.x.w a0, ft0
466 ; RV64IF-LABEL: fcvt_s_w_i8:
468 ; RV64IF-NEXT: fcvt.s.w ft0, a0
469 ; RV64IF-NEXT: fmv.x.w a0, ft0
471 %1 = sitofp i8 %a to float
475 define float @fcvt_s_wu_i8(i8 zeroext %a) nounwind {
476 ; RV32IF-LABEL: fcvt_s_wu_i8:
478 ; RV32IF-NEXT: fcvt.s.wu ft0, a0
479 ; RV32IF-NEXT: fmv.x.w a0, ft0
482 ; RV64IF-LABEL: fcvt_s_wu_i8:
484 ; RV64IF-NEXT: fcvt.s.wu ft0, a0
485 ; RV64IF-NEXT: fmv.x.w a0, ft0
487 %1 = uitofp i8 %a to float
491 define float @fcvt_s_w_i16(i16 signext %a) nounwind {
492 ; RV32IF-LABEL: fcvt_s_w_i16:
494 ; RV32IF-NEXT: fcvt.s.w ft0, a0
495 ; RV32IF-NEXT: fmv.x.w a0, ft0
498 ; RV64IF-LABEL: fcvt_s_w_i16:
500 ; RV64IF-NEXT: fcvt.s.w ft0, a0
501 ; RV64IF-NEXT: fmv.x.w a0, ft0
503 %1 = sitofp i16 %a to float
507 define float @fcvt_s_wu_i16(i16 zeroext %a) nounwind {
508 ; RV32IF-LABEL: fcvt_s_wu_i16:
510 ; RV32IF-NEXT: fcvt.s.wu ft0, a0
511 ; RV32IF-NEXT: fmv.x.w a0, ft0
514 ; RV64IF-LABEL: fcvt_s_wu_i16:
516 ; RV64IF-NEXT: fcvt.s.wu ft0, a0
517 ; RV64IF-NEXT: fmv.x.w a0, ft0
519 %1 = uitofp i16 %a to float