These are fp->int conversions using either RMM or dynamic rounding modes.
The lround and lrint opcodes have a return type of either i32 or
i64 depending on sizeof(long) in the frontend which should follow
xlen. llround/llrint should always return i64 so we'll need a libcall
for those on rv32.
The frontend will only emit the intrinsics if -fno-math-errno is in
effect otherwise a libcall will be emitted which will not use
these ISD opcodes.
gcc also does this optimization.
Reviewed By: arcbbb
Differential Revision: https://reviews.llvm.org/D105206
if (Subtarget.hasStdExtZfh()) {
setOperationAction(ISD::FMINNUM, MVT::f16, Legal);
setOperationAction(ISD::FMAXNUM, MVT::f16, Legal);
+ setOperationAction(ISD::LRINT, MVT::f16, Legal);
+ setOperationAction(ISD::LLRINT, MVT::f16, Legal);
+ setOperationAction(ISD::LROUND, MVT::f16, Legal);
+ setOperationAction(ISD::LLROUND, MVT::f16, Legal);
for (auto CC : FPCCToExpand)
setCondCodeAction(CC, MVT::f16, Expand);
setOperationAction(ISD::SELECT_CC, MVT::f16, Expand);
if (Subtarget.hasStdExtF()) {
setOperationAction(ISD::FMINNUM, MVT::f32, Legal);
setOperationAction(ISD::FMAXNUM, MVT::f32, Legal);
+ setOperationAction(ISD::LRINT, MVT::f32, Legal);
+ setOperationAction(ISD::LLRINT, MVT::f32, Legal);
+ setOperationAction(ISD::LROUND, MVT::f32, Legal);
+ setOperationAction(ISD::LLROUND, MVT::f32, Legal);
for (auto CC : FPCCToExpand)
setCondCodeAction(CC, MVT::f32, Expand);
setOperationAction(ISD::SELECT_CC, MVT::f32, Expand);
if (Subtarget.hasStdExtD()) {
setOperationAction(ISD::FMINNUM, MVT::f64, Legal);
setOperationAction(ISD::FMAXNUM, MVT::f64, Legal);
+ setOperationAction(ISD::LRINT, MVT::f64, Legal);
+ setOperationAction(ISD::LLRINT, MVT::f64, Legal);
+ setOperationAction(ISD::LROUND, MVT::f64, Legal);
+ setOperationAction(ISD::LLROUND, MVT::f64, Legal);
for (auto CC : FPCCToExpand)
setCondCodeAction(CC, MVT::f64, Expand);
setOperationAction(ISD::SELECT_CC, MVT::f64, Expand);
def : Pat<(i32 (fp_to_sint FPR64:$rs1)), (FCVT_W_D FPR64:$rs1, 0b001)>;
def : Pat<(i32 (fp_to_uint FPR64:$rs1)), (FCVT_WU_D FPR64:$rs1, 0b001)>;
+// float->int32 with current rounding mode.
+def : Pat<(i32 (lrint FPR64:$rs1)), (FCVT_W_D $rs1, 0b111)>;
+
+// float->int32 rounded to nearest with ties rounded away from zero.
+def : Pat<(i32 (lround FPR64:$rs1)), (FCVT_W_D $rs1, 0b100)>;
+
// [u]int->double.
def : Pat<(sint_to_fp (i32 GPR:$rs1)), (FCVT_D_W GPR:$rs1)>;
def : Pat<(uint_to_fp (i32 GPR:$rs1)), (FCVT_D_WU GPR:$rs1)>;
def : Pat<(sint_to_fp (i64 (sexti32 (i64 GPR:$rs1)))), (FCVT_D_W $rs1)>;
def : Pat<(uint_to_fp (i64 (zexti32 (i64 GPR:$rs1)))), (FCVT_D_WU $rs1)>;
+// double->[u]int64. Round-to-zero must be used.
def : Pat<(i64 (fp_to_sint FPR64:$rs1)), (FCVT_L_D FPR64:$rs1, 0b001)>;
def : Pat<(i64 (fp_to_uint FPR64:$rs1)), (FCVT_LU_D FPR64:$rs1, 0b001)>;
+// double->int64 with current rounding mode.
+def : Pat<(i64 (lrint FPR64:$rs1)), (FCVT_L_D $rs1, 0b111)>;
+def : Pat<(i64 (llrint FPR64:$rs1)), (FCVT_L_D $rs1, 0b111)>;
+
+// double->int64 rounded to nearest with ties rounded away from zero.
+def : Pat<(i64 (lround FPR64:$rs1)), (FCVT_L_D $rs1, 0b100)>;
+def : Pat<(i64 (llround FPR64:$rs1)), (FCVT_L_D $rs1, 0b100)>;
+
// [u]int64->fp. Match GCC and default to using dynamic rounding mode.
def : Pat<(sint_to_fp (i64 GPR:$rs1)), (FCVT_D_L GPR:$rs1, 0b111)>;
def : Pat<(uint_to_fp (i64 GPR:$rs1)), (FCVT_D_LU GPR:$rs1, 0b111)>;
def : Pat<(i32 (fp_to_sint FPR32:$rs1)), (FCVT_W_S $rs1, 0b001)>;
def : Pat<(i32 (fp_to_uint FPR32:$rs1)), (FCVT_WU_S $rs1, 0b001)>;
+// float->int32 with current rounding mode.
+def : Pat<(i32 (lrint FPR32:$rs1)), (FCVT_W_S $rs1, 0b111)>;
+
+// float->int32 rounded to nearest with ties rounded away from zero.
+def : Pat<(i32 (lround FPR32:$rs1)), (FCVT_W_S $rs1, 0b100)>;
+
// [u]int->float. Match GCC and default to using dynamic rounding mode.
def : Pat<(sint_to_fp (i32 GPR:$rs1)), (FCVT_S_W $rs1, 0b111)>;
def : Pat<(uint_to_fp (i32 GPR:$rs1)), (FCVT_S_WU $rs1, 0b111)>;
def : Pat<(sext_inreg (assertzexti32 (fp_to_uint FPR32:$rs1)), i32),
(FCVT_WU_S $rs1, 0b001)>;
-// FP->[u]int64
+// float->[u]int64. Round-to-zero must be used.
def : Pat<(i64 (fp_to_sint FPR32:$rs1)), (FCVT_L_S $rs1, 0b001)>;
def : Pat<(i64 (fp_to_uint FPR32:$rs1)), (FCVT_LU_S $rs1, 0b001)>;
+// float->int64 with current rounding mode.
+def : Pat<(i64 (lrint FPR32:$rs1)), (FCVT_L_S $rs1, 0b111)>;
+def : Pat<(i64 (llrint FPR32:$rs1)), (FCVT_L_S $rs1, 0b111)>;
+
+// float->int64 rounded to neartest with ties rounded away from zero.
+def : Pat<(i64 (lround FPR32:$rs1)), (FCVT_L_S $rs1, 0b100)>;
+def : Pat<(i64 (llround FPR32:$rs1)), (FCVT_L_S $rs1, 0b100)>;
+
// [u]int->fp. Match GCC and default to using dynamic rounding mode.
def : Pat<(sint_to_fp (i64 (sexti32 (i64 GPR:$rs1)))), (FCVT_S_W $rs1, 0b111)>;
def : Pat<(uint_to_fp (i64 (zexti32 (i64 GPR:$rs1)))), (FCVT_S_WU $rs1, 0b111)>;
} // Predicates = [HasStdExtZfh]
let Predicates = [HasStdExtZfh, IsRV32] in {
-// float->[u]int. Round-to-zero must be used.
+// half->[u]int. Round-to-zero must be used.
def : Pat<(i32 (fp_to_sint FPR16:$rs1)), (FCVT_W_H $rs1, 0b001)>;
def : Pat<(i32 (fp_to_uint FPR16:$rs1)), (FCVT_WU_H $rs1, 0b001)>;
-// [u]int->float. Match GCC and default to using dynamic rounding mode.
+// half->int32 with current rounding mode.
+def : Pat<(i32 (lrint FPR16:$rs1)), (FCVT_W_H $rs1, 0b111)>;
+
+// half->int32 rounded to nearest with ties rounded away from zero.
+def : Pat<(i32 (lround FPR16:$rs1)), (FCVT_W_H $rs1, 0b100)>;
+
+// [u]int->half. Match GCC and default to using dynamic rounding mode.
def : Pat<(sint_to_fp (i32 GPR:$rs1)), (FCVT_H_W $rs1, 0b111)>;
def : Pat<(uint_to_fp (i32 GPR:$rs1)), (FCVT_H_WU $rs1, 0b111)>;
} // Predicates = [HasStdExtZfh, IsRV32]
def : Pat<(sext_inreg (assertzexti32 (fp_to_uint FPR16:$rs1)), i32),
(FCVT_WU_H $rs1, 0b001)>;
-// FP->[u]int64
+// half->[u]int64. Round-to-zero must be used.
def : Pat<(i64 (fp_to_sint FPR16:$rs1)), (FCVT_L_H $rs1, 0b001)>;
def : Pat<(i64 (fp_to_uint FPR16:$rs1)), (FCVT_LU_H $rs1, 0b001)>;
+// half->int64 with current rounding mode.
+def : Pat<(i64 (lrint FPR16:$rs1)), (FCVT_L_H $rs1, 0b111)>;
+def : Pat<(i64 (llrint FPR16:$rs1)), (FCVT_L_H $rs1, 0b111)>;
+
+// half->int64 rounded to nearest with ties rounded away from zero.
+def : Pat<(i64 (lround FPR16:$rs1)), (FCVT_L_H $rs1, 0b100)>;
+def : Pat<(i64 (llround FPR16:$rs1)), (FCVT_L_H $rs1, 0b100)>;
+
// [u]int->fp. Match GCC and default to using dynamic rounding mode.
def : Pat<(sint_to_fp (i64 (sexti32 (i64 GPR:$rs1)))), (FCVT_H_W $rs1, 0b111)>;
def : Pat<(uint_to_fp (i64 (zexti32 (i64 GPR:$rs1)))), (FCVT_H_WU $rs1, 0b111)>;
; 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
+; RUN: sed 's/iXLen/i32/g' %s | llc -mtriple=riscv32 -mattr=+d \
+; RUN: -verify-machineinstrs | FileCheck -check-prefix=RV32IFD %s
+; RUN: sed 's/iXLen/i64/g' %s | llc -mtriple=riscv64 -mattr=+d \
+; RUN: -verify-machineinstrs | FileCheck -check-prefix=RV64IFD %s
declare double @llvm.sqrt.f64(double)
%1 = call double @llvm.round.f64(double %a)
ret double %1
}
+
+declare iXLen @llvm.lrint.iXLen.f64(float)
+
+define iXLen @lrint_f64(float %a) nounwind {
+; RV32IFD-LABEL: lrint_f64:
+; RV32IFD: # %bb.0:
+; RV32IFD-NEXT: fmv.w.x ft0, a0
+; RV32IFD-NEXT: fcvt.w.s a0, ft0
+; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: lrint_f64:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.w.x ft0, a0
+; RV64IFD-NEXT: fcvt.l.s a0, ft0
+; RV64IFD-NEXT: ret
+ %1 = call iXLen @llvm.lrint.iXLen.f64(float %a)
+ ret iXLen %1
+}
+
+declare iXLen @llvm.lround.iXLen.f64(float)
+
+define iXLen @lround_f64(float %a) nounwind {
+; RV32IFD-LABEL: lround_f64:
+; RV32IFD: # %bb.0:
+; RV32IFD-NEXT: fmv.w.x ft0, a0
+; RV32IFD-NEXT: fcvt.w.s a0, ft0, rmm
+; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: lround_f64:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.w.x ft0, a0
+; RV64IFD-NEXT: fcvt.l.s a0, ft0, rmm
+; RV64IFD-NEXT: ret
+ %1 = call iXLen @llvm.lround.iXLen.f64(float %a)
+ ret iXLen %1
+}
+
+declare i64 @llvm.llrint.i64.f64(float)
+
+define i64 @llrint_f64(float %a) nounwind {
+; RV32IFD-LABEL: llrint_f64:
+; RV32IFD: # %bb.0:
+; RV32IFD-NEXT: addi sp, sp, -16
+; RV32IFD-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
+; RV32IFD-NEXT: call llrintf@plt
+; RV32IFD-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
+; RV32IFD-NEXT: addi sp, sp, 16
+; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: llrint_f64:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.w.x ft0, a0
+; RV64IFD-NEXT: fcvt.l.s a0, ft0
+; RV64IFD-NEXT: ret
+ %1 = call i64 @llvm.llrint.i64.f64(float %a)
+ ret i64 %1
+}
+
+declare i64 @llvm.llround.i64.f64(float)
+
+define i64 @llround_f64(float %a) nounwind {
+; RV32IFD-LABEL: llround_f64:
+; RV32IFD: # %bb.0:
+; RV32IFD-NEXT: addi sp, sp, -16
+; RV32IFD-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
+; RV32IFD-NEXT: call llroundf@plt
+; RV32IFD-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
+; RV32IFD-NEXT: addi sp, sp, 16
+; RV32IFD-NEXT: ret
+;
+; RV64IFD-LABEL: llround_f64:
+; RV64IFD: # %bb.0:
+; RV64IFD-NEXT: fmv.w.x ft0, a0
+; RV64IFD-NEXT: fcvt.l.s a0, ft0, rmm
+; RV64IFD-NEXT: ret
+ %1 = call i64 @llvm.llround.i64.f64(float %a)
+ ret i64 %1
+}
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; RUN: llc -mtriple=riscv32 -mattr=+f -verify-machineinstrs < %s \
-; RUN: | FileCheck -check-prefix=RV32IF %s
-; RUN: llc -mtriple=riscv32 -mattr=+d -verify-machineinstrs < %s \
-; RUN: | FileCheck -check-prefix=RV32IF %s
-; RUN: llc -mtriple=riscv64 -mattr=+f -verify-machineinstrs < %s \
-; RUN: | FileCheck -check-prefix=RV64IF %s
-; RUN: llc -mtriple=riscv64 -mattr=+d -verify-machineinstrs < %s \
-; RUN: | FileCheck -check-prefix=RV64IF %s
+; RUN: sed 's/iXLen/i32/g' %s | llc -mtriple=riscv32 -mattr=+f \
+; RUN: -verify-machineinstrs | FileCheck -check-prefix=RV32IF %s
+; RUN: sed 's/iXLen/i32/g' %s | llc -mtriple=riscv32 -mattr=+d \
+; RUN: -verify-machineinstrs | FileCheck -check-prefix=RV32IF %s
+; RUN: sed 's/iXLen/i64/g' %s | llc -mtriple=riscv64 -mattr=+f \
+; RUN: -verify-machineinstrs | FileCheck -check-prefix=RV64IF %s
+; RUN: sed 's/iXLen/i64/g' %s | llc -mtriple=riscv64 -mattr=+d \
+; RUN: -verify-machineinstrs | FileCheck -check-prefix=RV64IF %s
declare float @llvm.sqrt.f32(float)
%1 = call float @llvm.round.f32(float %a)
ret float %1
}
+
+declare iXLen @llvm.lrint.iXLen.f32(float)
+
+define iXLen @lrint_f32(float %a) nounwind {
+; RV32IF-LABEL: lrint_f32:
+; RV32IF: # %bb.0:
+; RV32IF-NEXT: fmv.w.x ft0, a0
+; RV32IF-NEXT: fcvt.w.s a0, ft0
+; RV32IF-NEXT: ret
+;
+; RV64IF-LABEL: lrint_f32:
+; RV64IF: # %bb.0:
+; RV64IF-NEXT: fmv.w.x ft0, a0
+; RV64IF-NEXT: fcvt.l.s a0, ft0
+; RV64IF-NEXT: ret
+ %1 = call iXLen @llvm.lrint.iXLen.f32(float %a)
+ ret iXLen %1
+}
+
+declare iXLen @llvm.lround.iXLen.f32(float)
+
+define iXLen @lround_f32(float %a) nounwind {
+; RV32IF-LABEL: lround_f32:
+; RV32IF: # %bb.0:
+; RV32IF-NEXT: fmv.w.x ft0, a0
+; RV32IF-NEXT: fcvt.w.s a0, ft0, rmm
+; RV32IF-NEXT: ret
+;
+; RV64IF-LABEL: lround_f32:
+; RV64IF: # %bb.0:
+; RV64IF-NEXT: fmv.w.x ft0, a0
+; RV64IF-NEXT: fcvt.l.s a0, ft0, rmm
+; RV64IF-NEXT: ret
+ %1 = call iXLen @llvm.lround.iXLen.f32(float %a)
+ ret iXLen %1
+}
+
+declare i64 @llvm.llrint.i64.f32(float)
+
+define i64 @llrint_f32(float %a) nounwind {
+; RV32IF-LABEL: llrint_f32:
+; RV32IF: # %bb.0:
+; RV32IF-NEXT: addi sp, sp, -16
+; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
+; RV32IF-NEXT: call llrintf@plt
+; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
+; RV32IF-NEXT: addi sp, sp, 16
+; RV32IF-NEXT: ret
+;
+; RV64IF-LABEL: llrint_f32:
+; RV64IF: # %bb.0:
+; RV64IF-NEXT: fmv.w.x ft0, a0
+; RV64IF-NEXT: fcvt.l.s a0, ft0
+; RV64IF-NEXT: ret
+ %1 = call i64 @llvm.llrint.i64.f32(float %a)
+ ret i64 %1
+}
+
+declare i64 @llvm.llround.i64.f32(float)
+
+define i64 @llround_f32(float %a) nounwind {
+; RV32IF-LABEL: llround_f32:
+; RV32IF: # %bb.0:
+; RV32IF-NEXT: addi sp, sp, -16
+; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
+; RV32IF-NEXT: call llroundf@plt
+; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
+; RV32IF-NEXT: addi sp, sp, 16
+; RV32IF-NEXT: ret
+;
+; RV64IF-LABEL: llround_f32:
+; RV64IF: # %bb.0:
+; RV64IF-NEXT: fmv.w.x ft0, a0
+; RV64IF-NEXT: fcvt.l.s a0, ft0, rmm
+; RV64IF-NEXT: ret
+ %1 = call i64 @llvm.llround.i64.f32(float %a)
+ ret i64 %1
+}
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; RUN: llc -mtriple=riscv32 -mattr=+experimental-zfh -verify-machineinstrs \
-; RUN: -target-abi ilp32f < %s | FileCheck -check-prefix=RV32IZFH %s
-; RUN: llc -mtriple=riscv32 -mattr=+d -mattr=+experimental-zfh -verify-machineinstrs \
-; RUN: -target-abi ilp32d < %s | FileCheck -check-prefix=RV32IDZFH %s
-; RUN: llc -mtriple=riscv64 -mattr=+experimental-zfh -verify-machineinstrs \
-; RUN: -target-abi lp64f < %s | FileCheck -check-prefix=RV64IZFH %s
-; RUN: llc -mtriple=riscv64 -mattr=+d -mattr=+experimental-zfh -verify-machineinstrs \
-; RUN: -target-abi lp64d < %s | FileCheck -check-prefix=RV64IDZFH %s
+; RUN: sed 's/iXLen/i32/g' %s | llc -mtriple=riscv32 -mattr=+experimental-zfh \
+; RUN: -verify-machineinstrs -target-abi ilp32f | \
+; RUN: FileCheck -check-prefix=RV32IZFH %s
+; RUN: sed 's/iXLen/i32/g' %s | llc -mtriple=riscv32 -mattr=+d \
+; RUN: -mattr=+experimental-zfh -verify-machineinstrs -target-abi ilp32d | \
+; RUN: FileCheck -check-prefix=RV32IDZFH %s
+; RUN: sed 's/iXLen/i64/g' %s | llc -mtriple=riscv64 -mattr=+experimental-zfh \
+; RUN: -verify-machineinstrs -target-abi lp64f | \
+; RUN: FileCheck -check-prefix=RV64IZFH %s
+; RUN: sed 's/iXLen/i64/g' %s | llc -mtriple=riscv64 -mattr=+d \
+; RUN: -mattr=+experimental-zfh -verify-machineinstrs -target-abi lp64d | \
+; RUN: FileCheck -check-prefix=RV64IDZFH %s
declare half @llvm.sqrt.f16(half)
%1 = call half @llvm.copysign.f16(half %a, half %b)
ret half %1
}
+
+declare iXLen @llvm.lrint.iXLen.f16(float)
+
+define iXLen @lrint_f16(float %a) nounwind {
+; RV32IZFH-LABEL: lrint_f16:
+; RV32IZFH: # %bb.0:
+; RV32IZFH-NEXT: fcvt.w.s a0, fa0
+; RV32IZFH-NEXT: ret
+;
+; RV32IDZFH-LABEL: lrint_f16:
+; RV32IDZFH: # %bb.0:
+; RV32IDZFH-NEXT: fcvt.w.s a0, fa0
+; RV32IDZFH-NEXT: ret
+;
+; RV64IZFH-LABEL: lrint_f16:
+; RV64IZFH: # %bb.0:
+; RV64IZFH-NEXT: fcvt.l.s a0, fa0
+; RV64IZFH-NEXT: ret
+;
+; RV64IDZFH-LABEL: lrint_f16:
+; RV64IDZFH: # %bb.0:
+; RV64IDZFH-NEXT: fcvt.l.s a0, fa0
+; RV64IDZFH-NEXT: ret
+ %1 = call iXLen @llvm.lrint.iXLen.f16(float %a)
+ ret iXLen %1
+}
+
+declare iXLen @llvm.lround.iXLen.f16(float)
+
+define iXLen @lround_f16(float %a) nounwind {
+; RV32IZFH-LABEL: lround_f16:
+; RV32IZFH: # %bb.0:
+; RV32IZFH-NEXT: fcvt.w.s a0, fa0, rmm
+; RV32IZFH-NEXT: ret
+;
+; RV32IDZFH-LABEL: lround_f16:
+; RV32IDZFH: # %bb.0:
+; RV32IDZFH-NEXT: fcvt.w.s a0, fa0, rmm
+; RV32IDZFH-NEXT: ret
+;
+; RV64IZFH-LABEL: lround_f16:
+; RV64IZFH: # %bb.0:
+; RV64IZFH-NEXT: fcvt.l.s a0, fa0, rmm
+; RV64IZFH-NEXT: ret
+;
+; RV64IDZFH-LABEL: lround_f16:
+; RV64IDZFH: # %bb.0:
+; RV64IDZFH-NEXT: fcvt.l.s a0, fa0, rmm
+; RV64IDZFH-NEXT: ret
+ %1 = call iXLen @llvm.lround.iXLen.f16(float %a)
+ ret iXLen %1
+}
+
+declare i64 @llvm.llrint.i64.f16(float)
+
+define i64 @llrint_f16(float %a) nounwind {
+; RV32IZFH-LABEL: llrint_f16:
+; RV32IZFH: # %bb.0:
+; RV32IZFH-NEXT: addi sp, sp, -16
+; RV32IZFH-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
+; RV32IZFH-NEXT: call llrintf@plt
+; RV32IZFH-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
+; RV32IZFH-NEXT: addi sp, sp, 16
+; RV32IZFH-NEXT: ret
+;
+; RV32IDZFH-LABEL: llrint_f16:
+; RV32IDZFH: # %bb.0:
+; RV32IDZFH-NEXT: addi sp, sp, -16
+; RV32IDZFH-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
+; RV32IDZFH-NEXT: call llrintf@plt
+; RV32IDZFH-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
+; RV32IDZFH-NEXT: addi sp, sp, 16
+; RV32IDZFH-NEXT: ret
+;
+; RV64IZFH-LABEL: llrint_f16:
+; RV64IZFH: # %bb.0:
+; RV64IZFH-NEXT: fcvt.l.s a0, fa0
+; RV64IZFH-NEXT: ret
+;
+; RV64IDZFH-LABEL: llrint_f16:
+; RV64IDZFH: # %bb.0:
+; RV64IDZFH-NEXT: fcvt.l.s a0, fa0
+; RV64IDZFH-NEXT: ret
+ %1 = call i64 @llvm.llrint.i64.f16(float %a)
+ ret i64 %1
+}
+
+declare i64 @llvm.llround.i64.f16(float)
+
+define i64 @llround_f16(float %a) nounwind {
+; RV32IZFH-LABEL: llround_f16:
+; RV32IZFH: # %bb.0:
+; RV32IZFH-NEXT: addi sp, sp, -16
+; RV32IZFH-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
+; RV32IZFH-NEXT: call llroundf@plt
+; RV32IZFH-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
+; RV32IZFH-NEXT: addi sp, sp, 16
+; RV32IZFH-NEXT: ret
+;
+; RV32IDZFH-LABEL: llround_f16:
+; RV32IDZFH: # %bb.0:
+; RV32IDZFH-NEXT: addi sp, sp, -16
+; RV32IDZFH-NEXT: sw ra, 12(sp) # 4-byte Folded Spill
+; RV32IDZFH-NEXT: call llroundf@plt
+; RV32IDZFH-NEXT: lw ra, 12(sp) # 4-byte Folded Reload
+; RV32IDZFH-NEXT: addi sp, sp, 16
+; RV32IDZFH-NEXT: ret
+;
+; RV64IZFH-LABEL: llround_f16:
+; RV64IZFH: # %bb.0:
+; RV64IZFH-NEXT: fcvt.l.s a0, fa0, rmm
+; RV64IZFH-NEXT: ret
+;
+; RV64IDZFH-LABEL: llround_f16:
+; RV64IDZFH: # %bb.0:
+; RV64IDZFH-NEXT: fcvt.l.s a0, fa0, rmm
+; RV64IDZFH-NEXT: ret
+ %1 = call i64 @llvm.llround.i64.f16(float %a)
+ ret i64 %1
+}