The fcvt fp to integer instructions saturate if their input is infinity or out of range, but the instructions produce a maximum integer for nan instead of 0 required for the ISD opcodes. This means we can use the instructions to do the saturating conversion, but we'll need to fix up the nan case at the end. We can probably improve the i8 and i16 default codegen as well, but I'll leave that for a follow up. Reviewed By: luismarques Differential Revision: https://reviews.llvm.org/D107230
635 lines
19 KiB
LLVM
635 lines
19 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
|
|
; RUN: llc -mtriple=riscv32 -mattr=+d -verify-machineinstrs < %s \
|
|
; RUN: | FileCheck -check-prefix=RV32IFD %s
|
|
; RUN: llc -mtriple=riscv64 -mattr=+d -verify-machineinstrs < %s \
|
|
; RUN: | FileCheck -check-prefix=RV64IFD %s
|
|
|
|
define float @fcvt_s_d(double %a) nounwind {
|
|
; RV32IFD-LABEL: fcvt_s_d:
|
|
; RV32IFD: # %bb.0:
|
|
; RV32IFD-NEXT: addi sp, sp, -16
|
|
; RV32IFD-NEXT: sw a0, 8(sp)
|
|
; RV32IFD-NEXT: sw a1, 12(sp)
|
|
; RV32IFD-NEXT: fld ft0, 8(sp)
|
|
; RV32IFD-NEXT: fcvt.s.d ft0, ft0
|
|
; RV32IFD-NEXT: fmv.x.w a0, ft0
|
|
; RV32IFD-NEXT: addi sp, sp, 16
|
|
; RV32IFD-NEXT: ret
|
|
;
|
|
; RV64IFD-LABEL: fcvt_s_d:
|
|
; RV64IFD: # %bb.0:
|
|
; RV64IFD-NEXT: fmv.d.x ft0, a0
|
|
; RV64IFD-NEXT: fcvt.s.d ft0, ft0
|
|
; RV64IFD-NEXT: fmv.x.w a0, ft0
|
|
; RV64IFD-NEXT: ret
|
|
%1 = fptrunc double %a to float
|
|
ret float %1
|
|
}
|
|
|
|
define double @fcvt_d_s(float %a) nounwind {
|
|
; RV32IFD-LABEL: fcvt_d_s:
|
|
; RV32IFD: # %bb.0:
|
|
; RV32IFD-NEXT: addi sp, sp, -16
|
|
; RV32IFD-NEXT: fmv.w.x ft0, a0
|
|
; RV32IFD-NEXT: fcvt.d.s ft0, ft0
|
|
; RV32IFD-NEXT: fsd ft0, 8(sp)
|
|
; RV32IFD-NEXT: lw a0, 8(sp)
|
|
; RV32IFD-NEXT: lw a1, 12(sp)
|
|
; RV32IFD-NEXT: addi sp, sp, 16
|
|
; RV32IFD-NEXT: ret
|
|
;
|
|
; RV64IFD-LABEL: fcvt_d_s:
|
|
; RV64IFD: # %bb.0:
|
|
; RV64IFD-NEXT: fmv.w.x ft0, a0
|
|
; RV64IFD-NEXT: fcvt.d.s ft0, ft0
|
|
; RV64IFD-NEXT: fmv.x.d a0, ft0
|
|
; RV64IFD-NEXT: ret
|
|
%1 = fpext float %a to double
|
|
ret double %1
|
|
}
|
|
|
|
; For RV64D, fcvt.l.d is semantically equivalent to fcvt.w.d in this case
|
|
; because fptosi will produce poison if the result doesn't fit into an i32.
|
|
define i32 @fcvt_w_d(double %a) nounwind {
|
|
; RV32IFD-LABEL: fcvt_w_d:
|
|
; RV32IFD: # %bb.0:
|
|
; RV32IFD-NEXT: addi sp, sp, -16
|
|
; RV32IFD-NEXT: sw a0, 8(sp)
|
|
; RV32IFD-NEXT: sw a1, 12(sp)
|
|
; RV32IFD-NEXT: fld ft0, 8(sp)
|
|
; RV32IFD-NEXT: fcvt.w.d a0, ft0, rtz
|
|
; RV32IFD-NEXT: addi sp, sp, 16
|
|
; RV32IFD-NEXT: ret
|
|
;
|
|
; RV64IFD-LABEL: fcvt_w_d:
|
|
; RV64IFD: # %bb.0:
|
|
; RV64IFD-NEXT: fmv.d.x ft0, a0
|
|
; RV64IFD-NEXT: fcvt.w.d a0, ft0, rtz
|
|
; RV64IFD-NEXT: ret
|
|
%1 = fptosi double %a to i32
|
|
ret i32 %1
|
|
}
|
|
|
|
define i32 @fcvt_w_d_sat(double %a) nounwind {
|
|
; RV32IFD-LABEL: fcvt_w_d_sat:
|
|
; RV32IFD: # %bb.0: # %start
|
|
; RV32IFD-NEXT: addi sp, sp, -16
|
|
; RV32IFD-NEXT: sw a0, 8(sp)
|
|
; RV32IFD-NEXT: sw a1, 12(sp)
|
|
; RV32IFD-NEXT: fld ft0, 8(sp)
|
|
; RV32IFD-NEXT: feq.d a0, ft0, ft0
|
|
; RV32IFD-NEXT: bnez a0, .LBB3_2
|
|
; RV32IFD-NEXT: # %bb.1: # %start
|
|
; RV32IFD-NEXT: mv a0, zero
|
|
; RV32IFD-NEXT: addi sp, sp, 16
|
|
; RV32IFD-NEXT: ret
|
|
; RV32IFD-NEXT: .LBB3_2:
|
|
; RV32IFD-NEXT: fcvt.w.d a0, ft0, rtz
|
|
; RV32IFD-NEXT: addi sp, sp, 16
|
|
; RV32IFD-NEXT: ret
|
|
;
|
|
; RV64IFD-LABEL: fcvt_w_d_sat:
|
|
; RV64IFD: # %bb.0: # %start
|
|
; RV64IFD-NEXT: fmv.d.x ft0, a0
|
|
; RV64IFD-NEXT: feq.d a0, ft0, ft0
|
|
; RV64IFD-NEXT: bnez a0, .LBB3_2
|
|
; RV64IFD-NEXT: # %bb.1: # %start
|
|
; RV64IFD-NEXT: mv a0, zero
|
|
; RV64IFD-NEXT: ret
|
|
; RV64IFD-NEXT: .LBB3_2:
|
|
; RV64IFD-NEXT: fcvt.w.d a0, ft0, rtz
|
|
; RV64IFD-NEXT: ret
|
|
start:
|
|
%0 = tail call i32 @llvm.fptosi.sat.i32.f64(double %a)
|
|
ret i32 %0
|
|
}
|
|
declare i32 @llvm.fptosi.sat.i32.f64(double)
|
|
|
|
; For RV64D, fcvt.lu.d is semantically equivalent to fcvt.wu.d in this case
|
|
; because fptosi will produce poison if the result doesn't fit into an i32.
|
|
define i32 @fcvt_wu_d(double %a) nounwind {
|
|
; RV32IFD-LABEL: fcvt_wu_d:
|
|
; RV32IFD: # %bb.0:
|
|
; RV32IFD-NEXT: addi sp, sp, -16
|
|
; RV32IFD-NEXT: sw a0, 8(sp)
|
|
; RV32IFD-NEXT: sw a1, 12(sp)
|
|
; RV32IFD-NEXT: fld ft0, 8(sp)
|
|
; RV32IFD-NEXT: fcvt.wu.d a0, ft0, rtz
|
|
; RV32IFD-NEXT: addi sp, sp, 16
|
|
; RV32IFD-NEXT: ret
|
|
;
|
|
; RV64IFD-LABEL: fcvt_wu_d:
|
|
; RV64IFD: # %bb.0:
|
|
; RV64IFD-NEXT: fmv.d.x ft0, a0
|
|
; RV64IFD-NEXT: fcvt.wu.d a0, ft0, rtz
|
|
; RV64IFD-NEXT: ret
|
|
%1 = fptoui double %a to i32
|
|
ret i32 %1
|
|
}
|
|
|
|
; Test where the fptoui has multiple uses, one of which causes a sext to be
|
|
; inserted on RV64.
|
|
; FIXME: We should not have an fcvt.wu.d and an fcvt.lu.d.
|
|
define i32 @fcvt_wu_d_multiple_use(double %x, i32* %y) {
|
|
; RV32IFD-LABEL: fcvt_wu_d_multiple_use:
|
|
; RV32IFD: # %bb.0:
|
|
; RV32IFD-NEXT: addi sp, sp, -16
|
|
; RV32IFD-NEXT: .cfi_def_cfa_offset 16
|
|
; RV32IFD-NEXT: sw a0, 8(sp)
|
|
; RV32IFD-NEXT: sw a1, 12(sp)
|
|
; RV32IFD-NEXT: fld ft0, 8(sp)
|
|
; RV32IFD-NEXT: fcvt.wu.d a1, ft0, rtz
|
|
; RV32IFD-NEXT: addi a0, zero, 1
|
|
; RV32IFD-NEXT: beqz a1, .LBB5_2
|
|
; RV32IFD-NEXT: # %bb.1:
|
|
; RV32IFD-NEXT: mv a0, a1
|
|
; RV32IFD-NEXT: .LBB5_2:
|
|
; RV32IFD-NEXT: addi sp, sp, 16
|
|
; RV32IFD-NEXT: ret
|
|
;
|
|
; RV64IFD-LABEL: fcvt_wu_d_multiple_use:
|
|
; RV64IFD: # %bb.0:
|
|
; RV64IFD-NEXT: fmv.d.x ft0, a0
|
|
; RV64IFD-NEXT: fcvt.wu.d a1, ft0, rtz
|
|
; RV64IFD-NEXT: addi a0, zero, 1
|
|
; RV64IFD-NEXT: beqz a1, .LBB5_2
|
|
; RV64IFD-NEXT: # %bb.1:
|
|
; RV64IFD-NEXT: mv a0, a1
|
|
; RV64IFD-NEXT: .LBB5_2:
|
|
; RV64IFD-NEXT: ret
|
|
%a = fptoui double %x to i32
|
|
%b = icmp eq i32 %a, 0
|
|
%c = select i1 %b, i32 1, i32 %a
|
|
ret i32 %c
|
|
}
|
|
|
|
define i32 @fcvt_wu_d_sat(double %a) nounwind {
|
|
; RV32IFD-LABEL: fcvt_wu_d_sat:
|
|
; RV32IFD: # %bb.0: # %start
|
|
; RV32IFD-NEXT: addi sp, sp, -16
|
|
; RV32IFD-NEXT: sw a0, 8(sp)
|
|
; RV32IFD-NEXT: sw a1, 12(sp)
|
|
; RV32IFD-NEXT: fld ft0, 8(sp)
|
|
; RV32IFD-NEXT: feq.d a0, ft0, ft0
|
|
; RV32IFD-NEXT: bnez a0, .LBB6_2
|
|
; RV32IFD-NEXT: # %bb.1: # %start
|
|
; RV32IFD-NEXT: mv a0, zero
|
|
; RV32IFD-NEXT: addi sp, sp, 16
|
|
; RV32IFD-NEXT: ret
|
|
; RV32IFD-NEXT: .LBB6_2:
|
|
; RV32IFD-NEXT: fcvt.wu.d a0, ft0, rtz
|
|
; RV32IFD-NEXT: addi sp, sp, 16
|
|
; RV32IFD-NEXT: ret
|
|
;
|
|
; RV64IFD-LABEL: fcvt_wu_d_sat:
|
|
; RV64IFD: # %bb.0: # %start
|
|
; RV64IFD-NEXT: fmv.d.x ft0, a0
|
|
; RV64IFD-NEXT: feq.d a0, ft0, ft0
|
|
; RV64IFD-NEXT: bnez a0, .LBB6_2
|
|
; RV64IFD-NEXT: # %bb.1: # %start
|
|
; RV64IFD-NEXT: mv a0, zero
|
|
; RV64IFD-NEXT: ret
|
|
; RV64IFD-NEXT: .LBB6_2:
|
|
; RV64IFD-NEXT: fcvt.wu.d a0, ft0, rtz
|
|
; RV64IFD-NEXT: ret
|
|
start:
|
|
%0 = tail call i32 @llvm.fptoui.sat.i32.f64(double %a)
|
|
ret i32 %0
|
|
}
|
|
declare i32 @llvm.fptoui.sat.i32.f64(double)
|
|
|
|
define double @fcvt_d_w(i32 %a) nounwind {
|
|
; RV32IFD-LABEL: fcvt_d_w:
|
|
; RV32IFD: # %bb.0:
|
|
; RV32IFD-NEXT: addi sp, sp, -16
|
|
; RV32IFD-NEXT: fcvt.d.w ft0, a0
|
|
; RV32IFD-NEXT: fsd ft0, 8(sp)
|
|
; RV32IFD-NEXT: lw a0, 8(sp)
|
|
; RV32IFD-NEXT: lw a1, 12(sp)
|
|
; RV32IFD-NEXT: addi sp, sp, 16
|
|
; RV32IFD-NEXT: ret
|
|
;
|
|
; RV64IFD-LABEL: fcvt_d_w:
|
|
; RV64IFD: # %bb.0:
|
|
; RV64IFD-NEXT: fcvt.d.w ft0, a0
|
|
; RV64IFD-NEXT: fmv.x.d a0, ft0
|
|
; RV64IFD-NEXT: ret
|
|
%1 = sitofp i32 %a to double
|
|
ret double %1
|
|
}
|
|
|
|
define double @fcvt_d_w_load(i32* %p) nounwind {
|
|
; RV32IFD-LABEL: fcvt_d_w_load:
|
|
; RV32IFD: # %bb.0:
|
|
; RV32IFD-NEXT: addi sp, sp, -16
|
|
; RV32IFD-NEXT: lw a0, 0(a0)
|
|
; RV32IFD-NEXT: fcvt.d.w ft0, a0
|
|
; RV32IFD-NEXT: fsd ft0, 8(sp)
|
|
; RV32IFD-NEXT: lw a0, 8(sp)
|
|
; RV32IFD-NEXT: lw a1, 12(sp)
|
|
; RV32IFD-NEXT: addi sp, sp, 16
|
|
; RV32IFD-NEXT: ret
|
|
;
|
|
; RV64IFD-LABEL: fcvt_d_w_load:
|
|
; RV64IFD: # %bb.0:
|
|
; RV64IFD-NEXT: lw a0, 0(a0)
|
|
; RV64IFD-NEXT: fcvt.d.w ft0, a0
|
|
; RV64IFD-NEXT: fmv.x.d a0, ft0
|
|
; RV64IFD-NEXT: ret
|
|
%a = load i32, i32* %p
|
|
%1 = sitofp i32 %a to double
|
|
ret double %1
|
|
}
|
|
|
|
define double @fcvt_d_wu(i32 %a) nounwind {
|
|
; RV32IFD-LABEL: fcvt_d_wu:
|
|
; RV32IFD: # %bb.0:
|
|
; RV32IFD-NEXT: addi sp, sp, -16
|
|
; RV32IFD-NEXT: fcvt.d.wu ft0, a0
|
|
; RV32IFD-NEXT: fsd ft0, 8(sp)
|
|
; RV32IFD-NEXT: lw a0, 8(sp)
|
|
; RV32IFD-NEXT: lw a1, 12(sp)
|
|
; RV32IFD-NEXT: addi sp, sp, 16
|
|
; RV32IFD-NEXT: ret
|
|
;
|
|
; RV64IFD-LABEL: fcvt_d_wu:
|
|
; RV64IFD: # %bb.0:
|
|
; RV64IFD-NEXT: fcvt.d.wu ft0, a0
|
|
; RV64IFD-NEXT: fmv.x.d a0, ft0
|
|
; RV64IFD-NEXT: ret
|
|
%1 = uitofp i32 %a to double
|
|
ret double %1
|
|
}
|
|
|
|
define double @fcvt_d_wu_load(i32* %p) nounwind {
|
|
; RV32IFD-LABEL: fcvt_d_wu_load:
|
|
; RV32IFD: # %bb.0:
|
|
; RV32IFD-NEXT: addi sp, sp, -16
|
|
; RV32IFD-NEXT: lw a0, 0(a0)
|
|
; RV32IFD-NEXT: fcvt.d.wu ft0, a0
|
|
; RV32IFD-NEXT: fsd ft0, 8(sp)
|
|
; RV32IFD-NEXT: lw a0, 8(sp)
|
|
; RV32IFD-NEXT: lw a1, 12(sp)
|
|
; RV32IFD-NEXT: addi sp, sp, 16
|
|
; RV32IFD-NEXT: ret
|
|
;
|
|
; RV64IFD-LABEL: fcvt_d_wu_load:
|
|
; RV64IFD: # %bb.0:
|
|
; RV64IFD-NEXT: lwu a0, 0(a0)
|
|
; RV64IFD-NEXT: fcvt.d.wu ft0, a0
|
|
; RV64IFD-NEXT: fmv.x.d a0, ft0
|
|
; RV64IFD-NEXT: ret
|
|
%a = load i32, i32* %p
|
|
%1 = uitofp i32 %a to double
|
|
ret double %1
|
|
}
|
|
|
|
define i64 @fcvt_l_d(double %a) nounwind {
|
|
; RV32IFD-LABEL: fcvt_l_d:
|
|
; RV32IFD: # %bb.0:
|
|
; RV32IFD-NEXT: addi sp, sp, -16
|
|
; RV32IFD-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
|
|
; RV32IFD-NEXT: call __fixdfdi@plt
|
|
; RV32IFD-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
|
|
; RV32IFD-NEXT: addi sp, sp, 16
|
|
; RV32IFD-NEXT: ret
|
|
;
|
|
; RV64IFD-LABEL: fcvt_l_d:
|
|
; RV64IFD: # %bb.0:
|
|
; RV64IFD-NEXT: fmv.d.x ft0, a0
|
|
; RV64IFD-NEXT: fcvt.l.d a0, ft0, rtz
|
|
; RV64IFD-NEXT: ret
|
|
%1 = fptosi double %a to i64
|
|
ret i64 %1
|
|
}
|
|
|
|
define i64 @fcvt_l_d_sat(double %a) nounwind {
|
|
; RV32IFD-LABEL: fcvt_l_d_sat:
|
|
; RV32IFD: # %bb.0: # %start
|
|
; RV32IFD-NEXT: addi sp, sp, -32
|
|
; RV32IFD-NEXT: sw ra, 28(sp) # 4-byte Folded Spill
|
|
; RV32IFD-NEXT: sw a0, 16(sp)
|
|
; RV32IFD-NEXT: sw a1, 20(sp)
|
|
; RV32IFD-NEXT: fld ft0, 16(sp)
|
|
; RV32IFD-NEXT: fsd ft0, 8(sp) # 8-byte Folded Spill
|
|
; RV32IFD-NEXT: call __fixdfdi@plt
|
|
; RV32IFD-NEXT: fld ft1, 8(sp) # 8-byte Folded Reload
|
|
; RV32IFD-NEXT: lui a2, %hi(.LCPI12_0)
|
|
; RV32IFD-NEXT: fld ft0, %lo(.LCPI12_0)(a2)
|
|
; RV32IFD-NEXT: fle.d a3, ft0, ft1
|
|
; RV32IFD-NEXT: mv a2, a0
|
|
; RV32IFD-NEXT: bnez a3, .LBB12_2
|
|
; RV32IFD-NEXT: # %bb.1: # %start
|
|
; RV32IFD-NEXT: mv a2, zero
|
|
; RV32IFD-NEXT: .LBB12_2: # %start
|
|
; RV32IFD-NEXT: lui a0, %hi(.LCPI12_1)
|
|
; RV32IFD-NEXT: fld ft0, %lo(.LCPI12_1)(a0)
|
|
; RV32IFD-NEXT: flt.d a4, ft0, ft1
|
|
; RV32IFD-NEXT: addi a0, zero, -1
|
|
; RV32IFD-NEXT: beqz a4, .LBB12_9
|
|
; RV32IFD-NEXT: # %bb.3: # %start
|
|
; RV32IFD-NEXT: feq.d a2, ft1, ft1
|
|
; RV32IFD-NEXT: beqz a2, .LBB12_10
|
|
; RV32IFD-NEXT: .LBB12_4: # %start
|
|
; RV32IFD-NEXT: lui a5, 524288
|
|
; RV32IFD-NEXT: beqz a3, .LBB12_11
|
|
; RV32IFD-NEXT: .LBB12_5: # %start
|
|
; RV32IFD-NEXT: bnez a4, .LBB12_12
|
|
; RV32IFD-NEXT: .LBB12_6: # %start
|
|
; RV32IFD-NEXT: bnez a2, .LBB12_8
|
|
; RV32IFD-NEXT: .LBB12_7: # %start
|
|
; RV32IFD-NEXT: mv a1, zero
|
|
; RV32IFD-NEXT: .LBB12_8: # %start
|
|
; RV32IFD-NEXT: lw ra, 28(sp) # 4-byte Folded Reload
|
|
; RV32IFD-NEXT: addi sp, sp, 32
|
|
; RV32IFD-NEXT: ret
|
|
; RV32IFD-NEXT: .LBB12_9: # %start
|
|
; RV32IFD-NEXT: mv a0, a2
|
|
; RV32IFD-NEXT: feq.d a2, ft1, ft1
|
|
; RV32IFD-NEXT: bnez a2, .LBB12_4
|
|
; RV32IFD-NEXT: .LBB12_10: # %start
|
|
; RV32IFD-NEXT: mv a0, zero
|
|
; RV32IFD-NEXT: lui a5, 524288
|
|
; RV32IFD-NEXT: bnez a3, .LBB12_5
|
|
; RV32IFD-NEXT: .LBB12_11: # %start
|
|
; RV32IFD-NEXT: lui a1, 524288
|
|
; RV32IFD-NEXT: beqz a4, .LBB12_6
|
|
; RV32IFD-NEXT: .LBB12_12:
|
|
; RV32IFD-NEXT: addi a1, a5, -1
|
|
; RV32IFD-NEXT: beqz a2, .LBB12_7
|
|
; RV32IFD-NEXT: j .LBB12_8
|
|
;
|
|
; RV64IFD-LABEL: fcvt_l_d_sat:
|
|
; RV64IFD: # %bb.0: # %start
|
|
; RV64IFD-NEXT: fmv.d.x ft0, a0
|
|
; RV64IFD-NEXT: feq.d a0, ft0, ft0
|
|
; RV64IFD-NEXT: bnez a0, .LBB12_2
|
|
; RV64IFD-NEXT: # %bb.1: # %start
|
|
; RV64IFD-NEXT: mv a0, zero
|
|
; RV64IFD-NEXT: ret
|
|
; RV64IFD-NEXT: .LBB12_2:
|
|
; RV64IFD-NEXT: fcvt.l.d a0, ft0, rtz
|
|
; RV64IFD-NEXT: ret
|
|
start:
|
|
%0 = tail call i64 @llvm.fptosi.sat.i64.f64(double %a)
|
|
ret i64 %0
|
|
}
|
|
declare i64 @llvm.fptosi.sat.i64.f64(double)
|
|
|
|
define i64 @fcvt_lu_d(double %a) nounwind {
|
|
; RV32IFD-LABEL: fcvt_lu_d:
|
|
; RV32IFD: # %bb.0:
|
|
; RV32IFD-NEXT: addi sp, sp, -16
|
|
; RV32IFD-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
|
|
; RV32IFD-NEXT: call __fixunsdfdi@plt
|
|
; RV32IFD-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
|
|
; RV32IFD-NEXT: addi sp, sp, 16
|
|
; RV32IFD-NEXT: ret
|
|
;
|
|
; RV64IFD-LABEL: fcvt_lu_d:
|
|
; RV64IFD: # %bb.0:
|
|
; RV64IFD-NEXT: fmv.d.x ft0, a0
|
|
; RV64IFD-NEXT: fcvt.lu.d a0, ft0, rtz
|
|
; RV64IFD-NEXT: ret
|
|
%1 = fptoui double %a to i64
|
|
ret i64 %1
|
|
}
|
|
|
|
define i64 @fcvt_lu_d_sat(double %a) nounwind {
|
|
; RV32IFD-LABEL: fcvt_lu_d_sat:
|
|
; RV32IFD: # %bb.0: # %start
|
|
; RV32IFD-NEXT: addi sp, sp, -32
|
|
; RV32IFD-NEXT: sw ra, 28(sp) # 4-byte Folded Spill
|
|
; RV32IFD-NEXT: sw a0, 16(sp)
|
|
; RV32IFD-NEXT: sw a1, 20(sp)
|
|
; RV32IFD-NEXT: fld ft0, 16(sp)
|
|
; RV32IFD-NEXT: fsd ft0, 8(sp) # 8-byte Folded Spill
|
|
; RV32IFD-NEXT: call __fixunsdfdi@plt
|
|
; RV32IFD-NEXT: fld ft1, 8(sp) # 8-byte Folded Reload
|
|
; RV32IFD-NEXT: fcvt.d.w ft0, zero
|
|
; RV32IFD-NEXT: fle.d a4, ft0, ft1
|
|
; RV32IFD-NEXT: mv a3, a0
|
|
; RV32IFD-NEXT: bnez a4, .LBB14_2
|
|
; RV32IFD-NEXT: # %bb.1: # %start
|
|
; RV32IFD-NEXT: mv a3, zero
|
|
; RV32IFD-NEXT: .LBB14_2: # %start
|
|
; RV32IFD-NEXT: lui a0, %hi(.LCPI14_0)
|
|
; RV32IFD-NEXT: fld ft0, %lo(.LCPI14_0)(a0)
|
|
; RV32IFD-NEXT: flt.d a5, ft0, ft1
|
|
; RV32IFD-NEXT: addi a2, zero, -1
|
|
; RV32IFD-NEXT: addi a0, zero, -1
|
|
; RV32IFD-NEXT: beqz a5, .LBB14_7
|
|
; RV32IFD-NEXT: # %bb.3: # %start
|
|
; RV32IFD-NEXT: beqz a4, .LBB14_8
|
|
; RV32IFD-NEXT: .LBB14_4: # %start
|
|
; RV32IFD-NEXT: bnez a5, .LBB14_6
|
|
; RV32IFD-NEXT: .LBB14_5: # %start
|
|
; RV32IFD-NEXT: mv a2, a1
|
|
; RV32IFD-NEXT: .LBB14_6: # %start
|
|
; RV32IFD-NEXT: mv a1, a2
|
|
; RV32IFD-NEXT: lw ra, 28(sp) # 4-byte Folded Reload
|
|
; RV32IFD-NEXT: addi sp, sp, 32
|
|
; RV32IFD-NEXT: ret
|
|
; RV32IFD-NEXT: .LBB14_7: # %start
|
|
; RV32IFD-NEXT: mv a0, a3
|
|
; RV32IFD-NEXT: bnez a4, .LBB14_4
|
|
; RV32IFD-NEXT: .LBB14_8: # %start
|
|
; RV32IFD-NEXT: mv a1, zero
|
|
; RV32IFD-NEXT: beqz a5, .LBB14_5
|
|
; RV32IFD-NEXT: j .LBB14_6
|
|
;
|
|
; RV64IFD-LABEL: fcvt_lu_d_sat:
|
|
; RV64IFD: # %bb.0: # %start
|
|
; RV64IFD-NEXT: fmv.d.x ft0, a0
|
|
; RV64IFD-NEXT: feq.d a0, ft0, ft0
|
|
; RV64IFD-NEXT: bnez a0, .LBB14_2
|
|
; RV64IFD-NEXT: # %bb.1: # %start
|
|
; RV64IFD-NEXT: mv a0, zero
|
|
; RV64IFD-NEXT: ret
|
|
; RV64IFD-NEXT: .LBB14_2:
|
|
; RV64IFD-NEXT: fcvt.lu.d a0, ft0, rtz
|
|
; RV64IFD-NEXT: ret
|
|
start:
|
|
%0 = tail call i64 @llvm.fptoui.sat.i64.f64(double %a)
|
|
ret i64 %0
|
|
}
|
|
declare i64 @llvm.fptoui.sat.i64.f64(double)
|
|
|
|
define i64 @fmv_x_d(double %a, double %b) nounwind {
|
|
; RV32IFD-LABEL: fmv_x_d:
|
|
; RV32IFD: # %bb.0:
|
|
; RV32IFD-NEXT: addi sp, sp, -16
|
|
; RV32IFD-NEXT: sw a2, 0(sp)
|
|
; RV32IFD-NEXT: sw a3, 4(sp)
|
|
; RV32IFD-NEXT: fld ft0, 0(sp)
|
|
; RV32IFD-NEXT: sw a0, 0(sp)
|
|
; RV32IFD-NEXT: sw a1, 4(sp)
|
|
; RV32IFD-NEXT: fld ft1, 0(sp)
|
|
; RV32IFD-NEXT: fadd.d ft0, ft1, ft0
|
|
; RV32IFD-NEXT: fsd ft0, 8(sp)
|
|
; RV32IFD-NEXT: lw a0, 8(sp)
|
|
; RV32IFD-NEXT: lw a1, 12(sp)
|
|
; RV32IFD-NEXT: addi sp, sp, 16
|
|
; RV32IFD-NEXT: ret
|
|
;
|
|
; RV64IFD-LABEL: fmv_x_d:
|
|
; RV64IFD: # %bb.0:
|
|
; RV64IFD-NEXT: fmv.d.x ft0, a1
|
|
; RV64IFD-NEXT: fmv.d.x ft1, a0
|
|
; RV64IFD-NEXT: fadd.d ft0, ft1, ft0
|
|
; RV64IFD-NEXT: fmv.x.d a0, ft0
|
|
; RV64IFD-NEXT: ret
|
|
%1 = fadd double %a, %b
|
|
%2 = bitcast double %1 to i64
|
|
ret i64 %2
|
|
}
|
|
|
|
define double @fcvt_d_l(i64 %a) nounwind {
|
|
; RV32IFD-LABEL: fcvt_d_l:
|
|
; RV32IFD: # %bb.0:
|
|
; RV32IFD-NEXT: addi sp, sp, -16
|
|
; RV32IFD-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
|
|
; RV32IFD-NEXT: call __floatdidf@plt
|
|
; RV32IFD-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
|
|
; RV32IFD-NEXT: addi sp, sp, 16
|
|
; RV32IFD-NEXT: ret
|
|
;
|
|
; RV64IFD-LABEL: fcvt_d_l:
|
|
; RV64IFD: # %bb.0:
|
|
; RV64IFD-NEXT: fcvt.d.l ft0, a0
|
|
; RV64IFD-NEXT: fmv.x.d a0, ft0
|
|
; RV64IFD-NEXT: ret
|
|
%1 = sitofp i64 %a to double
|
|
ret double %1
|
|
}
|
|
|
|
define double @fcvt_d_lu(i64 %a) nounwind {
|
|
; RV32IFD-LABEL: fcvt_d_lu:
|
|
; RV32IFD: # %bb.0:
|
|
; RV32IFD-NEXT: addi sp, sp, -16
|
|
; RV32IFD-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
|
|
; RV32IFD-NEXT: call __floatundidf@plt
|
|
; RV32IFD-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
|
|
; RV32IFD-NEXT: addi sp, sp, 16
|
|
; RV32IFD-NEXT: ret
|
|
;
|
|
; RV64IFD-LABEL: fcvt_d_lu:
|
|
; RV64IFD: # %bb.0:
|
|
; RV64IFD-NEXT: fcvt.d.lu ft0, a0
|
|
; RV64IFD-NEXT: fmv.x.d a0, ft0
|
|
; RV64IFD-NEXT: ret
|
|
%1 = uitofp i64 %a to double
|
|
ret double %1
|
|
}
|
|
|
|
define double @fmv_d_x(i64 %a, i64 %b) nounwind {
|
|
; Ensure fmv.w.x is generated even for a soft double calling convention
|
|
; RV32IFD-LABEL: fmv_d_x:
|
|
; RV32IFD: # %bb.0:
|
|
; RV32IFD-NEXT: addi sp, sp, -32
|
|
; RV32IFD-NEXT: sw a3, 20(sp)
|
|
; RV32IFD-NEXT: sw a2, 16(sp)
|
|
; RV32IFD-NEXT: sw a1, 28(sp)
|
|
; RV32IFD-NEXT: sw a0, 24(sp)
|
|
; RV32IFD-NEXT: fld ft0, 16(sp)
|
|
; RV32IFD-NEXT: fld ft1, 24(sp)
|
|
; RV32IFD-NEXT: fadd.d ft0, ft1, ft0
|
|
; RV32IFD-NEXT: fsd ft0, 8(sp)
|
|
; RV32IFD-NEXT: lw a0, 8(sp)
|
|
; RV32IFD-NEXT: lw a1, 12(sp)
|
|
; RV32IFD-NEXT: addi sp, sp, 32
|
|
; RV32IFD-NEXT: ret
|
|
;
|
|
; RV64IFD-LABEL: fmv_d_x:
|
|
; RV64IFD: # %bb.0:
|
|
; RV64IFD-NEXT: fmv.d.x ft0, a0
|
|
; RV64IFD-NEXT: fmv.d.x ft1, a1
|
|
; RV64IFD-NEXT: fadd.d ft0, ft0, ft1
|
|
; RV64IFD-NEXT: fmv.x.d a0, ft0
|
|
; RV64IFD-NEXT: ret
|
|
%1 = bitcast i64 %a to double
|
|
%2 = bitcast i64 %b to double
|
|
%3 = fadd double %1, %2
|
|
ret double %3
|
|
}
|
|
|
|
define double @fcvt_d_w_i8(i8 signext %a) nounwind {
|
|
; RV32IFD-LABEL: fcvt_d_w_i8:
|
|
; RV32IFD: # %bb.0:
|
|
; RV32IFD-NEXT: addi sp, sp, -16
|
|
; RV32IFD-NEXT: fcvt.d.w ft0, a0
|
|
; RV32IFD-NEXT: fsd ft0, 8(sp)
|
|
; RV32IFD-NEXT: lw a0, 8(sp)
|
|
; RV32IFD-NEXT: lw a1, 12(sp)
|
|
; RV32IFD-NEXT: addi sp, sp, 16
|
|
; RV32IFD-NEXT: ret
|
|
;
|
|
; RV64IFD-LABEL: fcvt_d_w_i8:
|
|
; RV64IFD: # %bb.0:
|
|
; RV64IFD-NEXT: fcvt.d.w ft0, a0
|
|
; RV64IFD-NEXT: fmv.x.d a0, ft0
|
|
; RV64IFD-NEXT: ret
|
|
%1 = sitofp i8 %a to double
|
|
ret double %1
|
|
}
|
|
|
|
define double @fcvt_d_wu_i8(i8 zeroext %a) nounwind {
|
|
; RV32IFD-LABEL: fcvt_d_wu_i8:
|
|
; RV32IFD: # %bb.0:
|
|
; RV32IFD-NEXT: addi sp, sp, -16
|
|
; RV32IFD-NEXT: fcvt.d.wu ft0, a0
|
|
; RV32IFD-NEXT: fsd ft0, 8(sp)
|
|
; RV32IFD-NEXT: lw a0, 8(sp)
|
|
; RV32IFD-NEXT: lw a1, 12(sp)
|
|
; RV32IFD-NEXT: addi sp, sp, 16
|
|
; RV32IFD-NEXT: ret
|
|
;
|
|
; RV64IFD-LABEL: fcvt_d_wu_i8:
|
|
; RV64IFD: # %bb.0:
|
|
; RV64IFD-NEXT: fcvt.d.wu ft0, a0
|
|
; RV64IFD-NEXT: fmv.x.d a0, ft0
|
|
; RV64IFD-NEXT: ret
|
|
%1 = uitofp i8 %a to double
|
|
ret double %1
|
|
}
|
|
|
|
define double @fcvt_d_w_i16(i16 signext %a) nounwind {
|
|
; RV32IFD-LABEL: fcvt_d_w_i16:
|
|
; RV32IFD: # %bb.0:
|
|
; RV32IFD-NEXT: addi sp, sp, -16
|
|
; RV32IFD-NEXT: fcvt.d.w ft0, a0
|
|
; RV32IFD-NEXT: fsd ft0, 8(sp)
|
|
; RV32IFD-NEXT: lw a0, 8(sp)
|
|
; RV32IFD-NEXT: lw a1, 12(sp)
|
|
; RV32IFD-NEXT: addi sp, sp, 16
|
|
; RV32IFD-NEXT: ret
|
|
;
|
|
; RV64IFD-LABEL: fcvt_d_w_i16:
|
|
; RV64IFD: # %bb.0:
|
|
; RV64IFD-NEXT: fcvt.d.w ft0, a0
|
|
; RV64IFD-NEXT: fmv.x.d a0, ft0
|
|
; RV64IFD-NEXT: ret
|
|
%1 = sitofp i16 %a to double
|
|
ret double %1
|
|
}
|
|
|
|
define double @fcvt_d_wu_i16(i16 zeroext %a) nounwind {
|
|
; RV32IFD-LABEL: fcvt_d_wu_i16:
|
|
; RV32IFD: # %bb.0:
|
|
; RV32IFD-NEXT: addi sp, sp, -16
|
|
; RV32IFD-NEXT: fcvt.d.wu ft0, a0
|
|
; RV32IFD-NEXT: fsd ft0, 8(sp)
|
|
; RV32IFD-NEXT: lw a0, 8(sp)
|
|
; RV32IFD-NEXT: lw a1, 12(sp)
|
|
; RV32IFD-NEXT: addi sp, sp, 16
|
|
; RV32IFD-NEXT: ret
|
|
;
|
|
; RV64IFD-LABEL: fcvt_d_wu_i16:
|
|
; RV64IFD: # %bb.0:
|
|
; RV64IFD-NEXT: fcvt.d.wu ft0, a0
|
|
; RV64IFD-NEXT: fmv.x.d a0, ft0
|
|
; RV64IFD-NEXT: ret
|
|
%1 = uitofp i16 %a to double
|
|
ret double %1
|
|
}
|