mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 03:02:36 +01:00
0a8fb0b4d7
I stumbled onto a case where our (sext_inreg (assertzexti32 (fptoui X)), i32) isel pattern can cause an fcvt.wu and fcvt.lu to be emitted if the assertzexti32 has an additional user. If we add a one use check it would just cause a fcvt.lu followed by a sext.w when only need a fcvt.wu to satisfy both users. To mitigate this I've added custom isel and new ISD opcodes for fcvt.wu. This allows us to keep know it started life as a conversion to i32 without needing to match multiple nodes. ComputeNumSignBits has been taught that this new nodes produces 33 sign bits. To prevent regressions when we need to zero extend the result of an (i32 (fptoui X)), I've added a DAG combine to convert it to an (i64 (fptoui X)) before type legalization. In most cases this would happen in InstCombine, but a zero_extend can be created for function returns or arguments. To keep everything consistent I've added new nodes for fptosi as well. Reviewed By: luismarques Differential Revision: https://reviews.llvm.org/D106346
673 lines
20 KiB
LLVM
673 lines
20 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: lui a0, %hi(.LCPI3_0)
|
|
; RV32IFD-NEXT: fld ft1, %lo(.LCPI3_0)(a0)
|
|
; RV32IFD-NEXT: lui a0, %hi(.LCPI3_1)
|
|
; RV32IFD-NEXT: fld ft2, %lo(.LCPI3_1)(a0)
|
|
; RV32IFD-NEXT: fmax.d ft0, ft0, ft1
|
|
; RV32IFD-NEXT: fmin.d ft0, ft0, ft2
|
|
; 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: lui a0, %hi(.LCPI3_0)
|
|
; RV64IFD-NEXT: fld ft1, %lo(.LCPI3_0)(a0)
|
|
; RV64IFD-NEXT: lui a0, %hi(.LCPI3_1)
|
|
; RV64IFD-NEXT: fld ft2, %lo(.LCPI3_1)(a0)
|
|
; RV64IFD-NEXT: fmax.d ft0, ft0, ft1
|
|
; RV64IFD-NEXT: fmin.d ft0, ft0, ft2
|
|
; RV64IFD-NEXT: fcvt.l.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: lui a0, %hi(.LCPI6_0)
|
|
; RV32IFD-NEXT: fld ft1, %lo(.LCPI6_0)(a0)
|
|
; RV32IFD-NEXT: fcvt.d.w ft2, zero
|
|
; RV32IFD-NEXT: fmax.d ft0, ft0, ft2
|
|
; RV32IFD-NEXT: fmin.d ft0, ft0, ft1
|
|
; 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: lui a1, %hi(.LCPI6_0)
|
|
; RV64IFD-NEXT: fld ft0, %lo(.LCPI6_0)(a1)
|
|
; RV64IFD-NEXT: fmv.d.x ft1, a0
|
|
; RV64IFD-NEXT: fmv.d.x ft2, zero
|
|
; RV64IFD-NEXT: fmax.d ft1, ft1, ft2
|
|
; RV64IFD-NEXT: fmin.d ft0, ft1, ft0
|
|
; RV64IFD-NEXT: fcvt.lu.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: lui a1, %hi(.LCPI12_0)
|
|
; RV64IFD-NEXT: fld ft1, %lo(.LCPI12_0)(a1)
|
|
; RV64IFD-NEXT: fmv.d.x ft0, a0
|
|
; RV64IFD-NEXT: fle.d a0, ft1, ft0
|
|
; RV64IFD-NEXT: addi a1, zero, -1
|
|
; RV64IFD-NEXT: bnez a0, .LBB12_2
|
|
; RV64IFD-NEXT: # %bb.1: # %start
|
|
; RV64IFD-NEXT: slli a0, a1, 63
|
|
; RV64IFD-NEXT: j .LBB12_3
|
|
; RV64IFD-NEXT: .LBB12_2:
|
|
; RV64IFD-NEXT: fcvt.l.d a0, ft0, rtz
|
|
; RV64IFD-NEXT: .LBB12_3: # %start
|
|
; RV64IFD-NEXT: lui a2, %hi(.LCPI12_1)
|
|
; RV64IFD-NEXT: fld ft1, %lo(.LCPI12_1)(a2)
|
|
; RV64IFD-NEXT: flt.d a2, ft1, ft0
|
|
; RV64IFD-NEXT: bnez a2, .LBB12_6
|
|
; RV64IFD-NEXT: # %bb.4: # %start
|
|
; RV64IFD-NEXT: feq.d a1, ft0, ft0
|
|
; RV64IFD-NEXT: beqz a1, .LBB12_7
|
|
; RV64IFD-NEXT: .LBB12_5: # %start
|
|
; RV64IFD-NEXT: ret
|
|
; RV64IFD-NEXT: .LBB12_6:
|
|
; RV64IFD-NEXT: srli a0, a1, 1
|
|
; RV64IFD-NEXT: feq.d a1, ft0, ft0
|
|
; RV64IFD-NEXT: bnez a1, .LBB12_5
|
|
; RV64IFD-NEXT: .LBB12_7: # %start
|
|
; RV64IFD-NEXT: mv a0, zero
|
|
; 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: fmv.d.x ft1, zero
|
|
; RV64IFD-NEXT: fle.d a0, ft1, ft0
|
|
; RV64IFD-NEXT: bnez a0, .LBB14_2
|
|
; RV64IFD-NEXT: # %bb.1: # %start
|
|
; RV64IFD-NEXT: mv a1, zero
|
|
; RV64IFD-NEXT: j .LBB14_3
|
|
; RV64IFD-NEXT: .LBB14_2:
|
|
; RV64IFD-NEXT: fcvt.lu.d a1, ft0, rtz
|
|
; RV64IFD-NEXT: .LBB14_3: # %start
|
|
; RV64IFD-NEXT: lui a0, %hi(.LCPI14_0)
|
|
; RV64IFD-NEXT: fld ft1, %lo(.LCPI14_0)(a0)
|
|
; RV64IFD-NEXT: flt.d a2, ft1, ft0
|
|
; RV64IFD-NEXT: addi a0, zero, -1
|
|
; RV64IFD-NEXT: bnez a2, .LBB14_5
|
|
; RV64IFD-NEXT: # %bb.4: # %start
|
|
; RV64IFD-NEXT: mv a0, a1
|
|
; RV64IFD-NEXT: .LBB14_5: # %start
|
|
; 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
|
|
}
|