diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -1040,7 +1040,11 @@ setTargetDAGCombine(ISD::OR); setTargetDAGCombine(ISD::XOR); setTargetDAGCombine(ISD::ANY_EXTEND); - setTargetDAGCombine(ISD::ZERO_EXTEND); + if (Subtarget.hasStdExtF()) { + setTargetDAGCombine(ISD::ZERO_EXTEND); + setTargetDAGCombine(ISD::FP_TO_SINT); + setTargetDAGCombine(ISD::FP_TO_UINT); + } if (Subtarget.hasVInstructions()) { setTargetDAGCombine(ISD::FCOPYSIGN); setTargetDAGCombine(ISD::MGATHER); @@ -7025,6 +7029,60 @@ return DAG.getNode(WMulOpc, DL, VT, Op0, Op1, Mask, VL); } +// Fold +// (fp_to_int (froundeven X)) -> fcvt X, rne +// (fp_to_int (ftrunc X)) -> fcvt X, rtz +// (fp_to_int (ffloor X)) -> fcvt X, rdn +// (fp_to_int (fceil X)) -> fcvt X, rup +// (fp_to_int (fround X)) -> fcvt X, rmm +// FIXME: We should also do this for fp_to_int_sat. +static SDValue performFP_TO_INTCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, + const RISCVSubtarget &Subtarget) { + SelectionDAG &DAG = DCI.DAG; + const TargetLowering &TLI = DAG.getTargetLoweringInfo(); + MVT XLenVT = Subtarget.getXLenVT(); + + // Only handle XLen or i32 types. Other types narrower than XLen will + // eventually be legalized to XLenVT. + EVT VT = N->getValueType(0); + if (VT != MVT::i32 && VT != XLenVT) + return SDValue(); + + SDValue Src = N->getOperand(0); + + // Ensure the FP type is also legal. + if (!TLI.isTypeLegal(Src.getValueType())) + return SDValue(); + + // Don't do this for f16 with Zfhmin and not Zfh. + if (Src.getValueType() == MVT::f16 && !Subtarget.hasStdExtZfh()) + return SDValue(); + + RISCVFPRndMode::RoundingMode FRM; + switch (Src->getOpcode()) { + default: + return SDValue(); + case ISD::FROUNDEVEN: FRM = RISCVFPRndMode::RNE; break; + case ISD::FTRUNC: FRM = RISCVFPRndMode::RTZ; break; + case ISD::FFLOOR: FRM = RISCVFPRndMode::RDN; break; + case ISD::FCEIL: FRM = RISCVFPRndMode::RUP; break; + case ISD::FROUND: FRM = RISCVFPRndMode::RMM; break; + } + + bool IsSigned = N->getOpcode() == ISD::FP_TO_SINT; + + unsigned Opc; + if (VT == XLenVT) + Opc = IsSigned ? RISCVISD::FCVT_X : RISCVISD::FCVT_XU; + else + Opc = IsSigned ? RISCVISD::FCVT_W_RV64 : RISCVISD::FCVT_WU_RV64; + + SDLoc DL(N); + SDValue FpToInt = DAG.getNode(Opc, DL, XLenVT, Src.getOperand(0), + DAG.getTargetConstant(FRM, DL, XLenVT)); + return DAG.getNode(ISD::TRUNCATE, DL, VT, FpToInt); +} + SDValue RISCVTargetLowering::PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI) const { SelectionDAG &DAG = DCI.DAG; @@ -7227,7 +7285,8 @@ // Fold (zero_extend (fp_to_uint X)) to prevent forming fcvt+zexti32 during // type legalization. This is safe because fp_to_uint produces poison if // it overflows. - if (N->getValueType(0) == MVT::i64 && Subtarget.is64Bit()) { + if (N->getValueType(0) == MVT::i64 && Subtarget.is64Bit() && + N->getOperand(0).getValueType() == MVT::i32) { SDValue Src = N->getOperand(0); if (Src.getOpcode() == ISD::FP_TO_UINT && isTypeLegal(Src.getOperand(0).getValueType())) @@ -7354,6 +7413,9 @@ } break; } + case ISD::FP_TO_SINT: + case ISD::FP_TO_UINT: + return performFP_TO_INTCombine(N, DCI, Subtarget); case ISD::FCOPYSIGN: { EVT VT = N->getValueType(0); if (!VT.isVector()) diff --git a/llvm/test/CodeGen/RISCV/double-round-conv.ll b/llvm/test/CodeGen/RISCV/double-round-conv.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/double-round-conv.ll @@ -0,0 +1,682 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -mattr=+d -verify-machineinstrs < %s \ +; RUN: -target-abi=ilp32d | FileCheck -check-prefix=RV32IF %s +; RUN: llc -mtriple=riscv64 -mattr=+d -verify-machineinstrs < %s \ +; RUN: -target-abi=lp64d | FileCheck -check-prefix=RV64IF %s + +define signext i8 @test_floor_si8(double %x) { +; RV32IF-LABEL: test_floor_si8: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.d a0, fa0, rdn +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_floor_si8: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.d a0, fa0, rdn +; RV64IF-NEXT: ret + %a = call double @llvm.floor.f64(double %x) + %b = fptosi double %a to i8 + ret i8 %b +} + +define signext i16 @test_floor_si16(double %x) { +; RV32IF-LABEL: test_floor_si16: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.d a0, fa0, rdn +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_floor_si16: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.d a0, fa0, rdn +; RV64IF-NEXT: ret + %a = call double @llvm.floor.f64(double %x) + %b = fptosi double %a to i16 + ret i16 %b +} + +define signext i32 @test_floor_si32(double %x) { +; RV32IF-LABEL: test_floor_si32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.d a0, fa0, rdn +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_floor_si32: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.w.d a0, fa0, rdn +; RV64IF-NEXT: ret + %a = call double @llvm.floor.f64(double %x) + %b = fptosi double %a to i32 + ret i32 %b +} + +define i64 @test_floor_si64(double %x) { +; RV32IF-LABEL: test_floor_si64: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: .cfi_def_cfa_offset 16 +; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; RV32IF-NEXT: .cfi_offset ra, -4 +; RV32IF-NEXT: call floor@plt +; RV32IF-NEXT: call __fixdfdi@plt +; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_floor_si64: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.d a0, fa0, rdn +; RV64IF-NEXT: ret + %a = call double @llvm.floor.f64(double %x) + %b = fptosi double %a to i64 + ret i64 %b +} + +define zeroext i8 @test_floor_ui8(double %x) { +; RV32IF-LABEL: test_floor_ui8: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.d a0, fa0, rdn +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_floor_ui8: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.d a0, fa0, rdn +; RV64IF-NEXT: ret + %a = call double @llvm.floor.f64(double %x) + %b = fptoui double %a to i8 + ret i8 %b +} + +define zeroext i16 @test_floor_ui16(double %x) { +; RV32IF-LABEL: test_floor_ui16: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.d a0, fa0, rdn +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_floor_ui16: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.d a0, fa0, rdn +; RV64IF-NEXT: ret + %a = call double @llvm.floor.f64(double %x) + %b = fptoui double %a to i16 + ret i16 %b +} + +define signext i32 @test_floor_ui32(double %x) { +; RV32IF-LABEL: test_floor_ui32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.d a0, fa0, rdn +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_floor_ui32: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.wu.d a0, fa0, rdn +; RV64IF-NEXT: ret + %a = call double @llvm.floor.f64(double %x) + %b = fptoui double %a to i32 + ret i32 %b +} + +define i64 @test_floor_ui64(double %x) { +; RV32IF-LABEL: test_floor_ui64: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: .cfi_def_cfa_offset 16 +; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; RV32IF-NEXT: .cfi_offset ra, -4 +; RV32IF-NEXT: call floor@plt +; RV32IF-NEXT: call __fixunsdfdi@plt +; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_floor_ui64: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.d a0, fa0, rdn +; RV64IF-NEXT: ret + %a = call double @llvm.floor.f64(double %x) + %b = fptoui double %a to i64 + ret i64 %b +} + +define signext i8 @test_ceil_si8(double %x) { +; RV32IF-LABEL: test_ceil_si8: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.d a0, fa0, rup +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_ceil_si8: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.d a0, fa0, rup +; RV64IF-NEXT: ret + %a = call double @llvm.ceil.f64(double %x) + %b = fptosi double %a to i8 + ret i8 %b +} + +define signext i16 @test_ceil_si16(double %x) { +; RV32IF-LABEL: test_ceil_si16: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.d a0, fa0, rup +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_ceil_si16: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.d a0, fa0, rup +; RV64IF-NEXT: ret + %a = call double @llvm.ceil.f64(double %x) + %b = fptosi double %a to i16 + ret i16 %b +} + +define signext i32 @test_ceil_si32(double %x) { +; RV32IF-LABEL: test_ceil_si32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.d a0, fa0, rup +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_ceil_si32: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.w.d a0, fa0, rup +; RV64IF-NEXT: ret + %a = call double @llvm.ceil.f64(double %x) + %b = fptosi double %a to i32 + ret i32 %b +} + +define i64 @test_ceil_si64(double %x) { +; RV32IF-LABEL: test_ceil_si64: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: .cfi_def_cfa_offset 16 +; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; RV32IF-NEXT: .cfi_offset ra, -4 +; RV32IF-NEXT: call ceil@plt +; RV32IF-NEXT: call __fixdfdi@plt +; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_ceil_si64: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.d a0, fa0, rup +; RV64IF-NEXT: ret + %a = call double @llvm.ceil.f64(double %x) + %b = fptosi double %a to i64 + ret i64 %b +} + +define zeroext i8 @test_ceil_ui8(double %x) { +; RV32IF-LABEL: test_ceil_ui8: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.d a0, fa0, rup +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_ceil_ui8: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.d a0, fa0, rup +; RV64IF-NEXT: ret + %a = call double @llvm.ceil.f64(double %x) + %b = fptoui double %a to i8 + ret i8 %b +} + +define zeroext i16 @test_ceil_ui16(double %x) { +; RV32IF-LABEL: test_ceil_ui16: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.d a0, fa0, rup +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_ceil_ui16: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.d a0, fa0, rup +; RV64IF-NEXT: ret + %a = call double @llvm.ceil.f64(double %x) + %b = fptoui double %a to i16 + ret i16 %b +} + +define signext i32 @test_ceil_ui32(double %x) { +; RV32IF-LABEL: test_ceil_ui32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.d a0, fa0, rup +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_ceil_ui32: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.wu.d a0, fa0, rup +; RV64IF-NEXT: ret + %a = call double @llvm.ceil.f64(double %x) + %b = fptoui double %a to i32 + ret i32 %b +} + +define i64 @test_ceil_ui64(double %x) { +; RV32IF-LABEL: test_ceil_ui64: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: .cfi_def_cfa_offset 16 +; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; RV32IF-NEXT: .cfi_offset ra, -4 +; RV32IF-NEXT: call ceil@plt +; RV32IF-NEXT: call __fixunsdfdi@plt +; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_ceil_ui64: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.d a0, fa0, rup +; RV64IF-NEXT: ret + %a = call double @llvm.ceil.f64(double %x) + %b = fptoui double %a to i64 + ret i64 %b +} + +define signext i8 @test_trunc_si8(double %x) { +; RV32IF-LABEL: test_trunc_si8: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.d a0, fa0, rtz +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_trunc_si8: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.d a0, fa0, rtz +; RV64IF-NEXT: ret + %a = call double @llvm.trunc.f64(double %x) + %b = fptosi double %a to i8 + ret i8 %b +} + +define signext i16 @test_trunc_si16(double %x) { +; RV32IF-LABEL: test_trunc_si16: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.d a0, fa0, rtz +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_trunc_si16: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.d a0, fa0, rtz +; RV64IF-NEXT: ret + %a = call double @llvm.trunc.f64(double %x) + %b = fptosi double %a to i16 + ret i16 %b +} + +define signext i32 @test_trunc_si32(double %x) { +; RV32IF-LABEL: test_trunc_si32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.d a0, fa0, rtz +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_trunc_si32: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.w.d a0, fa0, rtz +; RV64IF-NEXT: ret + %a = call double @llvm.trunc.f64(double %x) + %b = fptosi double %a to i32 + ret i32 %b +} + +define i64 @test_trunc_si64(double %x) { +; RV32IF-LABEL: test_trunc_si64: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: .cfi_def_cfa_offset 16 +; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; RV32IF-NEXT: .cfi_offset ra, -4 +; RV32IF-NEXT: call trunc@plt +; RV32IF-NEXT: call __fixdfdi@plt +; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_trunc_si64: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.d a0, fa0, rtz +; RV64IF-NEXT: ret + %a = call double @llvm.trunc.f64(double %x) + %b = fptosi double %a to i64 + ret i64 %b +} + +define zeroext i8 @test_trunc_ui8(double %x) { +; RV32IF-LABEL: test_trunc_ui8: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.d a0, fa0, rtz +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_trunc_ui8: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.d a0, fa0, rtz +; RV64IF-NEXT: ret + %a = call double @llvm.trunc.f64(double %x) + %b = fptoui double %a to i8 + ret i8 %b +} + +define zeroext i16 @test_trunc_ui16(double %x) { +; RV32IF-LABEL: test_trunc_ui16: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.d a0, fa0, rtz +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_trunc_ui16: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.d a0, fa0, rtz +; RV64IF-NEXT: ret + %a = call double @llvm.trunc.f64(double %x) + %b = fptoui double %a to i16 + ret i16 %b +} + +define signext i32 @test_trunc_ui32(double %x) { +; RV32IF-LABEL: test_trunc_ui32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.d a0, fa0, rtz +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_trunc_ui32: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.wu.d a0, fa0, rtz +; RV64IF-NEXT: ret + %a = call double @llvm.trunc.f64(double %x) + %b = fptoui double %a to i32 + ret i32 %b +} + +define i64 @test_trunc_ui64(double %x) { +; RV32IF-LABEL: test_trunc_ui64: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: .cfi_def_cfa_offset 16 +; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; RV32IF-NEXT: .cfi_offset ra, -4 +; RV32IF-NEXT: call trunc@plt +; RV32IF-NEXT: call __fixunsdfdi@plt +; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_trunc_ui64: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.d a0, fa0, rtz +; RV64IF-NEXT: ret + %a = call double @llvm.trunc.f64(double %x) + %b = fptoui double %a to i64 + ret i64 %b +} + +define signext i8 @test_round_si8(double %x) { +; RV32IF-LABEL: test_round_si8: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.d a0, fa0, rmm +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_round_si8: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.d a0, fa0, rmm +; RV64IF-NEXT: ret + %a = call double @llvm.round.f64(double %x) + %b = fptosi double %a to i8 + ret i8 %b +} + +define signext i16 @test_round_si16(double %x) { +; RV32IF-LABEL: test_round_si16: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.d a0, fa0, rmm +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_round_si16: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.d a0, fa0, rmm +; RV64IF-NEXT: ret + %a = call double @llvm.round.f64(double %x) + %b = fptosi double %a to i16 + ret i16 %b +} + +define signext i32 @test_round_si32(double %x) { +; RV32IF-LABEL: test_round_si32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.d a0, fa0, rmm +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_round_si32: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.w.d a0, fa0, rmm +; RV64IF-NEXT: ret + %a = call double @llvm.round.f64(double %x) + %b = fptosi double %a to i32 + ret i32 %b +} + +define i64 @test_round_si64(double %x) { +; RV32IF-LABEL: test_round_si64: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: .cfi_def_cfa_offset 16 +; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; RV32IF-NEXT: .cfi_offset ra, -4 +; RV32IF-NEXT: call round@plt +; RV32IF-NEXT: call __fixdfdi@plt +; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_round_si64: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.d a0, fa0, rmm +; RV64IF-NEXT: ret + %a = call double @llvm.round.f64(double %x) + %b = fptosi double %a to i64 + ret i64 %b +} + +define zeroext i8 @test_round_ui8(double %x) { +; RV32IF-LABEL: test_round_ui8: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.d a0, fa0, rmm +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_round_ui8: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.d a0, fa0, rmm +; RV64IF-NEXT: ret + %a = call double @llvm.round.f64(double %x) + %b = fptoui double %a to i8 + ret i8 %b +} + +define zeroext i16 @test_round_ui16(double %x) { +; RV32IF-LABEL: test_round_ui16: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.d a0, fa0, rmm +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_round_ui16: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.d a0, fa0, rmm +; RV64IF-NEXT: ret + %a = call double @llvm.round.f64(double %x) + %b = fptoui double %a to i16 + ret i16 %b +} + +define signext i32 @test_round_ui32(double %x) { +; RV32IF-LABEL: test_round_ui32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.d a0, fa0, rmm +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_round_ui32: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.wu.d a0, fa0, rmm +; RV64IF-NEXT: ret + %a = call double @llvm.round.f64(double %x) + %b = fptoui double %a to i32 + ret i32 %b +} + +define i64 @test_round_ui64(double %x) { +; RV32IF-LABEL: test_round_ui64: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: .cfi_def_cfa_offset 16 +; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; RV32IF-NEXT: .cfi_offset ra, -4 +; RV32IF-NEXT: call round@plt +; RV32IF-NEXT: call __fixunsdfdi@plt +; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_round_ui64: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.d a0, fa0, rmm +; RV64IF-NEXT: ret + %a = call double @llvm.round.f64(double %x) + %b = fptoui double %a to i64 + ret i64 %b +} + +define signext i8 @test_roundeven_si8(double %x) { +; RV32IF-LABEL: test_roundeven_si8: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.d a0, fa0, rne +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_roundeven_si8: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.d a0, fa0, rne +; RV64IF-NEXT: ret + %a = call double @llvm.roundeven.f64(double %x) + %b = fptosi double %a to i8 + ret i8 %b +} + +define signext i16 @test_roundeven_si16(double %x) { +; RV32IF-LABEL: test_roundeven_si16: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.d a0, fa0, rne +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_roundeven_si16: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.d a0, fa0, rne +; RV64IF-NEXT: ret + %a = call double @llvm.roundeven.f64(double %x) + %b = fptosi double %a to i16 + ret i16 %b +} + +define signext i32 @test_roundeven_si32(double %x) { +; RV32IF-LABEL: test_roundeven_si32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.d a0, fa0, rne +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_roundeven_si32: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.w.d a0, fa0, rne +; RV64IF-NEXT: ret + %a = call double @llvm.roundeven.f64(double %x) + %b = fptosi double %a to i32 + ret i32 %b +} + +define i64 @test_roundeven_si64(double %x) { +; RV32IF-LABEL: test_roundeven_si64: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: .cfi_def_cfa_offset 16 +; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; RV32IF-NEXT: .cfi_offset ra, -4 +; RV32IF-NEXT: call roundeven@plt +; RV32IF-NEXT: call __fixdfdi@plt +; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_roundeven_si64: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.d a0, fa0, rne +; RV64IF-NEXT: ret + %a = call double @llvm.roundeven.f64(double %x) + %b = fptosi double %a to i64 + ret i64 %b +} + +define zeroext i8 @test_roundeven_ui8(double %x) { +; RV32IF-LABEL: test_roundeven_ui8: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.d a0, fa0, rne +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_roundeven_ui8: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.d a0, fa0, rne +; RV64IF-NEXT: ret + %a = call double @llvm.roundeven.f64(double %x) + %b = fptoui double %a to i8 + ret i8 %b +} + +define zeroext i16 @test_roundeven_ui16(double %x) { +; RV32IF-LABEL: test_roundeven_ui16: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.d a0, fa0, rne +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_roundeven_ui16: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.d a0, fa0, rne +; RV64IF-NEXT: ret + %a = call double @llvm.roundeven.f64(double %x) + %b = fptoui double %a to i16 + ret i16 %b +} + +define signext i32 @test_roundeven_ui32(double %x) { +; RV32IF-LABEL: test_roundeven_ui32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.d a0, fa0, rne +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_roundeven_ui32: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.wu.d a0, fa0, rne +; RV64IF-NEXT: ret + %a = call double @llvm.roundeven.f64(double %x) + %b = fptoui double %a to i32 + ret i32 %b +} + +define i64 @test_roundeven_ui64(double %x) { +; RV32IF-LABEL: test_roundeven_ui64: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: .cfi_def_cfa_offset 16 +; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; RV32IF-NEXT: .cfi_offset ra, -4 +; RV32IF-NEXT: call roundeven@plt +; RV32IF-NEXT: call __fixunsdfdi@plt +; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_roundeven_ui64: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.d a0, fa0, rne +; RV64IF-NEXT: ret + %a = call double @llvm.roundeven.f64(double %x) + %b = fptoui double %a to i64 + ret i64 %b +} + + +declare double @llvm.floor.f64(double) +declare double @llvm.ceil.f64(double) +declare double @llvm.trunc.f64(double) +declare double @llvm.round.f64(double) +declare double @llvm.roundeven.f64(double) diff --git a/llvm/test/CodeGen/RISCV/float-round-conv.ll b/llvm/test/CodeGen/RISCV/float-round-conv.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/float-round-conv.ll @@ -0,0 +1,682 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -mattr=+f -verify-machineinstrs < %s \ +; RUN: -target-abi=ilp32f | FileCheck -check-prefix=RV32IF %s +; RUN: llc -mtriple=riscv64 -mattr=+f -verify-machineinstrs < %s \ +; RUN: -target-abi=lp64f | FileCheck -check-prefix=RV64IF %s + +define signext i8 @test_floor_si8(float %x) { +; RV32IF-LABEL: test_floor_si8: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.s a0, fa0, rdn +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_floor_si8: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.s a0, fa0, rdn +; RV64IF-NEXT: ret + %a = call float @llvm.floor.f32(float %x) + %b = fptosi float %a to i8 + ret i8 %b +} + +define signext i16 @test_floor_si16(float %x) { +; RV32IF-LABEL: test_floor_si16: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.s a0, fa0, rdn +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_floor_si16: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.s a0, fa0, rdn +; RV64IF-NEXT: ret + %a = call float @llvm.floor.f32(float %x) + %b = fptosi float %a to i16 + ret i16 %b +} + +define signext i32 @test_floor_si32(float %x) { +; RV32IF-LABEL: test_floor_si32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.s a0, fa0, rdn +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_floor_si32: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.w.s a0, fa0, rdn +; RV64IF-NEXT: ret + %a = call float @llvm.floor.f32(float %x) + %b = fptosi float %a to i32 + ret i32 %b +} + +define i64 @test_floor_si64(float %x) { +; RV32IF-LABEL: test_floor_si64: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: .cfi_def_cfa_offset 16 +; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; RV32IF-NEXT: .cfi_offset ra, -4 +; RV32IF-NEXT: call floorf@plt +; RV32IF-NEXT: call __fixsfdi@plt +; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_floor_si64: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.s a0, fa0, rdn +; RV64IF-NEXT: ret + %a = call float @llvm.floor.f32(float %x) + %b = fptosi float %a to i64 + ret i64 %b +} + +define zeroext i8 @test_floor_ui8(float %x) { +; RV32IF-LABEL: test_floor_ui8: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.s a0, fa0, rdn +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_floor_ui8: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.s a0, fa0, rdn +; RV64IF-NEXT: ret + %a = call float @llvm.floor.f32(float %x) + %b = fptoui float %a to i8 + ret i8 %b +} + +define zeroext i16 @test_floor_ui16(float %x) { +; RV32IF-LABEL: test_floor_ui16: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.s a0, fa0, rdn +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_floor_ui16: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.s a0, fa0, rdn +; RV64IF-NEXT: ret + %a = call float @llvm.floor.f32(float %x) + %b = fptoui float %a to i16 + ret i16 %b +} + +define signext i32 @test_floor_ui32(float %x) { +; RV32IF-LABEL: test_floor_ui32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.s a0, fa0, rdn +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_floor_ui32: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.wu.s a0, fa0, rdn +; RV64IF-NEXT: ret + %a = call float @llvm.floor.f32(float %x) + %b = fptoui float %a to i32 + ret i32 %b +} + +define i64 @test_floor_ui64(float %x) { +; RV32IF-LABEL: test_floor_ui64: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: .cfi_def_cfa_offset 16 +; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; RV32IF-NEXT: .cfi_offset ra, -4 +; RV32IF-NEXT: call floorf@plt +; RV32IF-NEXT: call __fixunssfdi@plt +; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_floor_ui64: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.s a0, fa0, rdn +; RV64IF-NEXT: ret + %a = call float @llvm.floor.f32(float %x) + %b = fptoui float %a to i64 + ret i64 %b +} + +define signext i8 @test_ceil_si8(float %x) { +; RV32IF-LABEL: test_ceil_si8: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.s a0, fa0, rup +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_ceil_si8: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.s a0, fa0, rup +; RV64IF-NEXT: ret + %a = call float @llvm.ceil.f32(float %x) + %b = fptosi float %a to i8 + ret i8 %b +} + +define signext i16 @test_ceil_si16(float %x) { +; RV32IF-LABEL: test_ceil_si16: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.s a0, fa0, rup +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_ceil_si16: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.s a0, fa0, rup +; RV64IF-NEXT: ret + %a = call float @llvm.ceil.f32(float %x) + %b = fptosi float %a to i16 + ret i16 %b +} + +define signext i32 @test_ceil_si32(float %x) { +; RV32IF-LABEL: test_ceil_si32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.s a0, fa0, rup +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_ceil_si32: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.w.s a0, fa0, rup +; RV64IF-NEXT: ret + %a = call float @llvm.ceil.f32(float %x) + %b = fptosi float %a to i32 + ret i32 %b +} + +define i64 @test_ceil_si64(float %x) { +; RV32IF-LABEL: test_ceil_si64: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: .cfi_def_cfa_offset 16 +; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; RV32IF-NEXT: .cfi_offset ra, -4 +; RV32IF-NEXT: call ceilf@plt +; RV32IF-NEXT: call __fixsfdi@plt +; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_ceil_si64: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.s a0, fa0, rup +; RV64IF-NEXT: ret + %a = call float @llvm.ceil.f32(float %x) + %b = fptosi float %a to i64 + ret i64 %b +} + +define zeroext i8 @test_ceil_ui8(float %x) { +; RV32IF-LABEL: test_ceil_ui8: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.s a0, fa0, rup +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_ceil_ui8: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.s a0, fa0, rup +; RV64IF-NEXT: ret + %a = call float @llvm.ceil.f32(float %x) + %b = fptoui float %a to i8 + ret i8 %b +} + +define zeroext i16 @test_ceil_ui16(float %x) { +; RV32IF-LABEL: test_ceil_ui16: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.s a0, fa0, rup +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_ceil_ui16: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.s a0, fa0, rup +; RV64IF-NEXT: ret + %a = call float @llvm.ceil.f32(float %x) + %b = fptoui float %a to i16 + ret i16 %b +} + +define signext i32 @test_ceil_ui32(float %x) { +; RV32IF-LABEL: test_ceil_ui32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.s a0, fa0, rup +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_ceil_ui32: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.wu.s a0, fa0, rup +; RV64IF-NEXT: ret + %a = call float @llvm.ceil.f32(float %x) + %b = fptoui float %a to i32 + ret i32 %b +} + +define i64 @test_ceil_ui64(float %x) { +; RV32IF-LABEL: test_ceil_ui64: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: .cfi_def_cfa_offset 16 +; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; RV32IF-NEXT: .cfi_offset ra, -4 +; RV32IF-NEXT: call ceilf@plt +; RV32IF-NEXT: call __fixunssfdi@plt +; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_ceil_ui64: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.s a0, fa0, rup +; RV64IF-NEXT: ret + %a = call float @llvm.ceil.f32(float %x) + %b = fptoui float %a to i64 + ret i64 %b +} + +define signext i8 @test_trunc_si8(float %x) { +; RV32IF-LABEL: test_trunc_si8: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.s a0, fa0, rtz +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_trunc_si8: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.s a0, fa0, rtz +; RV64IF-NEXT: ret + %a = call float @llvm.trunc.f32(float %x) + %b = fptosi float %a to i8 + ret i8 %b +} + +define signext i16 @test_trunc_si16(float %x) { +; RV32IF-LABEL: test_trunc_si16: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.s a0, fa0, rtz +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_trunc_si16: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.s a0, fa0, rtz +; RV64IF-NEXT: ret + %a = call float @llvm.trunc.f32(float %x) + %b = fptosi float %a to i16 + ret i16 %b +} + +define signext i32 @test_trunc_si32(float %x) { +; RV32IF-LABEL: test_trunc_si32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.s a0, fa0, rtz +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_trunc_si32: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.w.s a0, fa0, rtz +; RV64IF-NEXT: ret + %a = call float @llvm.trunc.f32(float %x) + %b = fptosi float %a to i32 + ret i32 %b +} + +define i64 @test_trunc_si64(float %x) { +; RV32IF-LABEL: test_trunc_si64: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: .cfi_def_cfa_offset 16 +; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; RV32IF-NEXT: .cfi_offset ra, -4 +; RV32IF-NEXT: call truncf@plt +; RV32IF-NEXT: call __fixsfdi@plt +; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_trunc_si64: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.s a0, fa0, rtz +; RV64IF-NEXT: ret + %a = call float @llvm.trunc.f32(float %x) + %b = fptosi float %a to i64 + ret i64 %b +} + +define zeroext i8 @test_trunc_ui8(float %x) { +; RV32IF-LABEL: test_trunc_ui8: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.s a0, fa0, rtz +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_trunc_ui8: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.s a0, fa0, rtz +; RV64IF-NEXT: ret + %a = call float @llvm.trunc.f32(float %x) + %b = fptoui float %a to i8 + ret i8 %b +} + +define zeroext i16 @test_trunc_ui16(float %x) { +; RV32IF-LABEL: test_trunc_ui16: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.s a0, fa0, rtz +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_trunc_ui16: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.s a0, fa0, rtz +; RV64IF-NEXT: ret + %a = call float @llvm.trunc.f32(float %x) + %b = fptoui float %a to i16 + ret i16 %b +} + +define signext i32 @test_trunc_ui32(float %x) { +; RV32IF-LABEL: test_trunc_ui32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.s a0, fa0, rtz +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_trunc_ui32: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.wu.s a0, fa0, rtz +; RV64IF-NEXT: ret + %a = call float @llvm.trunc.f32(float %x) + %b = fptoui float %a to i32 + ret i32 %b +} + +define i64 @test_trunc_ui64(float %x) { +; RV32IF-LABEL: test_trunc_ui64: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: .cfi_def_cfa_offset 16 +; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; RV32IF-NEXT: .cfi_offset ra, -4 +; RV32IF-NEXT: call truncf@plt +; RV32IF-NEXT: call __fixunssfdi@plt +; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_trunc_ui64: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.s a0, fa0, rtz +; RV64IF-NEXT: ret + %a = call float @llvm.trunc.f32(float %x) + %b = fptoui float %a to i64 + ret i64 %b +} + +define signext i8 @test_round_si8(float %x) { +; RV32IF-LABEL: test_round_si8: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.s a0, fa0, rmm +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_round_si8: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.s a0, fa0, rmm +; RV64IF-NEXT: ret + %a = call float @llvm.round.f32(float %x) + %b = fptosi float %a to i8 + ret i8 %b +} + +define signext i16 @test_round_si16(float %x) { +; RV32IF-LABEL: test_round_si16: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.s a0, fa0, rmm +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_round_si16: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.s a0, fa0, rmm +; RV64IF-NEXT: ret + %a = call float @llvm.round.f32(float %x) + %b = fptosi float %a to i16 + ret i16 %b +} + +define signext i32 @test_round_si32(float %x) { +; RV32IF-LABEL: test_round_si32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.s a0, fa0, rmm +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_round_si32: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.w.s a0, fa0, rmm +; RV64IF-NEXT: ret + %a = call float @llvm.round.f32(float %x) + %b = fptosi float %a to i32 + ret i32 %b +} + +define i64 @test_round_si64(float %x) { +; RV32IF-LABEL: test_round_si64: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: .cfi_def_cfa_offset 16 +; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; RV32IF-NEXT: .cfi_offset ra, -4 +; RV32IF-NEXT: call roundf@plt +; RV32IF-NEXT: call __fixsfdi@plt +; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_round_si64: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.s a0, fa0, rmm +; RV64IF-NEXT: ret + %a = call float @llvm.round.f32(float %x) + %b = fptosi float %a to i64 + ret i64 %b +} + +define zeroext i8 @test_round_ui8(float %x) { +; RV32IF-LABEL: test_round_ui8: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.s a0, fa0, rmm +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_round_ui8: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.s a0, fa0, rmm +; RV64IF-NEXT: ret + %a = call float @llvm.round.f32(float %x) + %b = fptoui float %a to i8 + ret i8 %b +} + +define zeroext i16 @test_round_ui16(float %x) { +; RV32IF-LABEL: test_round_ui16: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.s a0, fa0, rmm +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_round_ui16: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.s a0, fa0, rmm +; RV64IF-NEXT: ret + %a = call float @llvm.round.f32(float %x) + %b = fptoui float %a to i16 + ret i16 %b +} + +define signext i32 @test_round_ui32(float %x) { +; RV32IF-LABEL: test_round_ui32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.s a0, fa0, rmm +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_round_ui32: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.wu.s a0, fa0, rmm +; RV64IF-NEXT: ret + %a = call float @llvm.round.f32(float %x) + %b = fptoui float %a to i32 + ret i32 %b +} + +define i64 @test_round_ui64(float %x) { +; RV32IF-LABEL: test_round_ui64: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: .cfi_def_cfa_offset 16 +; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; RV32IF-NEXT: .cfi_offset ra, -4 +; RV32IF-NEXT: call roundf@plt +; RV32IF-NEXT: call __fixunssfdi@plt +; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_round_ui64: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.s a0, fa0, rmm +; RV64IF-NEXT: ret + %a = call float @llvm.round.f32(float %x) + %b = fptoui float %a to i64 + ret i64 %b +} + +define signext i8 @test_roundeven_si8(float %x) { +; RV32IF-LABEL: test_roundeven_si8: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.s a0, fa0, rne +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_roundeven_si8: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.s a0, fa0, rne +; RV64IF-NEXT: ret + %a = call float @llvm.roundeven.f32(float %x) + %b = fptosi float %a to i8 + ret i8 %b +} + +define signext i16 @test_roundeven_si16(float %x) { +; RV32IF-LABEL: test_roundeven_si16: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.s a0, fa0, rne +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_roundeven_si16: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.s a0, fa0, rne +; RV64IF-NEXT: ret + %a = call float @llvm.roundeven.f32(float %x) + %b = fptosi float %a to i16 + ret i16 %b +} + +define signext i32 @test_roundeven_si32(float %x) { +; RV32IF-LABEL: test_roundeven_si32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.s a0, fa0, rne +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_roundeven_si32: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.w.s a0, fa0, rne +; RV64IF-NEXT: ret + %a = call float @llvm.roundeven.f32(float %x) + %b = fptosi float %a to i32 + ret i32 %b +} + +define i64 @test_roundeven_si64(float %x) { +; RV32IF-LABEL: test_roundeven_si64: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: .cfi_def_cfa_offset 16 +; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; RV32IF-NEXT: .cfi_offset ra, -4 +; RV32IF-NEXT: call roundevenf@plt +; RV32IF-NEXT: call __fixsfdi@plt +; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_roundeven_si64: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.s a0, fa0, rne +; RV64IF-NEXT: ret + %a = call float @llvm.roundeven.f32(float %x) + %b = fptosi float %a to i64 + ret i64 %b +} + +define zeroext i8 @test_roundeven_ui8(float %x) { +; RV32IF-LABEL: test_roundeven_ui8: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.s a0, fa0, rne +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_roundeven_ui8: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.s a0, fa0, rne +; RV64IF-NEXT: ret + %a = call float @llvm.roundeven.f32(float %x) + %b = fptoui float %a to i8 + ret i8 %b +} + +define zeroext i16 @test_roundeven_ui16(float %x) { +; RV32IF-LABEL: test_roundeven_ui16: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.s a0, fa0, rne +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_roundeven_ui16: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.s a0, fa0, rne +; RV64IF-NEXT: ret + %a = call float @llvm.roundeven.f32(float %x) + %b = fptoui float %a to i16 + ret i16 %b +} + +define signext i32 @test_roundeven_ui32(float %x) { +; RV32IF-LABEL: test_roundeven_ui32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.s a0, fa0, rne +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_roundeven_ui32: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.wu.s a0, fa0, rne +; RV64IF-NEXT: ret + %a = call float @llvm.roundeven.f32(float %x) + %b = fptoui float %a to i32 + ret i32 %b +} + +define i64 @test_roundeven_ui64(float %x) { +; RV32IF-LABEL: test_roundeven_ui64: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: .cfi_def_cfa_offset 16 +; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; RV32IF-NEXT: .cfi_offset ra, -4 +; RV32IF-NEXT: call roundevenf@plt +; RV32IF-NEXT: call __fixunssfdi@plt +; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_roundeven_ui64: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.s a0, fa0, rne +; RV64IF-NEXT: ret + %a = call float @llvm.roundeven.f32(float %x) + %b = fptoui float %a to i64 + ret i64 %b +} + + +declare float @llvm.floor.f32(float) +declare float @llvm.ceil.f32(float) +declare float @llvm.trunc.f32(float) +declare float @llvm.round.f32(float) +declare float @llvm.roundeven.f32(float) diff --git a/llvm/test/CodeGen/RISCV/half-round-conv.ll b/llvm/test/CodeGen/RISCV/half-round-conv.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/half-round-conv.ll @@ -0,0 +1,701 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -mattr=+experimental-zfh -verify-machineinstrs < %s \ +; RUN: -target-abi=ilp32f | FileCheck -check-prefix=RV32IF %s +; RUN: llc -mtriple=riscv64 -mattr=+experimental-zfh -verify-machineinstrs < %s \ +; RUN: -target-abi=lp64f | FileCheck -check-prefix=RV64IF %s + +define signext i8 @test_floor_si8(half %x) { +; RV32IF-LABEL: test_floor_si8: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.h a0, fa0, rdn +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_floor_si8: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.h a0, fa0, rdn +; RV64IF-NEXT: ret + %a = call half @llvm.floor.f16(half %x) + %b = fptosi half %a to i8 + ret i8 %b +} + +define signext i16 @test_floor_si16(half %x) { +; RV32IF-LABEL: test_floor_si16: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.h a0, fa0, rdn +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_floor_si16: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.h a0, fa0, rdn +; RV64IF-NEXT: ret + %a = call half @llvm.floor.f16(half %x) + %b = fptosi half %a to i16 + ret i16 %b +} + +define signext i32 @test_floor_si32(half %x) { +; RV32IF-LABEL: test_floor_si32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.h a0, fa0, rdn +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_floor_si32: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.w.h a0, fa0, rdn +; RV64IF-NEXT: ret + %a = call half @llvm.floor.f16(half %x) + %b = fptosi half %a to i32 + ret i32 %b +} + +define i64 @test_floor_si64(half %x) { +; RV32IF-LABEL: test_floor_si64: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: .cfi_def_cfa_offset 16 +; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; RV32IF-NEXT: .cfi_offset ra, -4 +; RV32IF-NEXT: fcvt.s.h fa0, fa0 +; RV32IF-NEXT: call floorf@plt +; RV32IF-NEXT: fcvt.h.s fa0, fa0 +; RV32IF-NEXT: call __fixhfdi@plt +; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_floor_si64: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.h a0, fa0, rdn +; RV64IF-NEXT: ret + %a = call half @llvm.floor.f16(half %x) + %b = fptosi half %a to i64 + ret i64 %b +} + +define zeroext i8 @test_floor_ui8(half %x) { +; RV32IF-LABEL: test_floor_ui8: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.h a0, fa0, rdn +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_floor_ui8: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.h a0, fa0, rdn +; RV64IF-NEXT: ret + %a = call half @llvm.floor.f16(half %x) + %b = fptoui half %a to i8 + ret i8 %b +} + +define zeroext i16 @test_floor_ui16(half %x) { +; RV32IF-LABEL: test_floor_ui16: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.h a0, fa0, rdn +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_floor_ui16: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.h a0, fa0, rdn +; RV64IF-NEXT: ret + %a = call half @llvm.floor.f16(half %x) + %b = fptoui half %a to i16 + ret i16 %b +} + +define signext i32 @test_floor_ui32(half %x) { +; RV32IF-LABEL: test_floor_ui32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.h a0, fa0, rdn +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_floor_ui32: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.wu.h a0, fa0, rdn +; RV64IF-NEXT: ret + %a = call half @llvm.floor.f16(half %x) + %b = fptoui half %a to i32 + ret i32 %b +} + +define i64 @test_floor_ui64(half %x) { +; RV32IF-LABEL: test_floor_ui64: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: .cfi_def_cfa_offset 16 +; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; RV32IF-NEXT: .cfi_offset ra, -4 +; RV32IF-NEXT: fcvt.s.h fa0, fa0 +; RV32IF-NEXT: call floorf@plt +; RV32IF-NEXT: fcvt.h.s fa0, fa0 +; RV32IF-NEXT: call __fixunshfdi@plt +; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_floor_ui64: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.h a0, fa0, rdn +; RV64IF-NEXT: ret + %a = call half @llvm.floor.f16(half %x) + %b = fptoui half %a to i64 + ret i64 %b +} + +define signext i8 @test_ceil_si8(half %x) { +; RV32IF-LABEL: test_ceil_si8: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.h a0, fa0, rup +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_ceil_si8: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.h a0, fa0, rup +; RV64IF-NEXT: ret + %a = call half @llvm.ceil.f16(half %x) + %b = fptosi half %a to i8 + ret i8 %b +} + +define signext i16 @test_ceil_si16(half %x) { +; RV32IF-LABEL: test_ceil_si16: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.h a0, fa0, rup +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_ceil_si16: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.h a0, fa0, rup +; RV64IF-NEXT: ret + %a = call half @llvm.ceil.f16(half %x) + %b = fptosi half %a to i16 + ret i16 %b +} + +define signext i32 @test_ceil_si32(half %x) { +; RV32IF-LABEL: test_ceil_si32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.h a0, fa0, rup +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_ceil_si32: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.w.h a0, fa0, rup +; RV64IF-NEXT: ret + %a = call half @llvm.ceil.f16(half %x) + %b = fptosi half %a to i32 + ret i32 %b +} + +define i64 @test_ceil_si64(half %x) { +; RV32IF-LABEL: test_ceil_si64: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: .cfi_def_cfa_offset 16 +; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; RV32IF-NEXT: .cfi_offset ra, -4 +; RV32IF-NEXT: fcvt.s.h fa0, fa0 +; RV32IF-NEXT: call ceilf@plt +; RV32IF-NEXT: fcvt.h.s fa0, fa0 +; RV32IF-NEXT: call __fixhfdi@plt +; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_ceil_si64: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.h a0, fa0, rup +; RV64IF-NEXT: ret + %a = call half @llvm.ceil.f16(half %x) + %b = fptosi half %a to i64 + ret i64 %b +} + +define zeroext i8 @test_ceil_ui8(half %x) { +; RV32IF-LABEL: test_ceil_ui8: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.h a0, fa0, rup +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_ceil_ui8: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.h a0, fa0, rup +; RV64IF-NEXT: ret + %a = call half @llvm.ceil.f16(half %x) + %b = fptoui half %a to i8 + ret i8 %b +} + +define zeroext i16 @test_ceil_ui16(half %x) { +; RV32IF-LABEL: test_ceil_ui16: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.h a0, fa0, rup +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_ceil_ui16: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.h a0, fa0, rup +; RV64IF-NEXT: ret + %a = call half @llvm.ceil.f16(half %x) + %b = fptoui half %a to i16 + ret i16 %b +} + +define signext i32 @test_ceil_ui32(half %x) { +; RV32IF-LABEL: test_ceil_ui32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.h a0, fa0, rup +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_ceil_ui32: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.wu.h a0, fa0, rup +; RV64IF-NEXT: ret + %a = call half @llvm.ceil.f16(half %x) + %b = fptoui half %a to i32 + ret i32 %b +} + +define i64 @test_ceil_ui64(half %x) { +; RV32IF-LABEL: test_ceil_ui64: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: .cfi_def_cfa_offset 16 +; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; RV32IF-NEXT: .cfi_offset ra, -4 +; RV32IF-NEXT: fcvt.s.h fa0, fa0 +; RV32IF-NEXT: call ceilf@plt +; RV32IF-NEXT: fcvt.h.s fa0, fa0 +; RV32IF-NEXT: call __fixunshfdi@plt +; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_ceil_ui64: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.h a0, fa0, rup +; RV64IF-NEXT: ret + %a = call half @llvm.ceil.f16(half %x) + %b = fptoui half %a to i64 + ret i64 %b +} + +define signext i8 @test_trunc_si8(half %x) { +; RV32IF-LABEL: test_trunc_si8: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.h a0, fa0, rtz +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_trunc_si8: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.h a0, fa0, rtz +; RV64IF-NEXT: ret + %a = call half @llvm.trunc.f16(half %x) + %b = fptosi half %a to i8 + ret i8 %b +} + +define signext i16 @test_trunc_si16(half %x) { +; RV32IF-LABEL: test_trunc_si16: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.h a0, fa0, rtz +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_trunc_si16: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.h a0, fa0, rtz +; RV64IF-NEXT: ret + %a = call half @llvm.trunc.f16(half %x) + %b = fptosi half %a to i16 + ret i16 %b +} + +define signext i32 @test_trunc_si32(half %x) { +; RV32IF-LABEL: test_trunc_si32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.h a0, fa0, rtz +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_trunc_si32: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.w.h a0, fa0, rtz +; RV64IF-NEXT: ret + %a = call half @llvm.trunc.f16(half %x) + %b = fptosi half %a to i32 + ret i32 %b +} + +define i64 @test_trunc_si64(half %x) { +; RV32IF-LABEL: test_trunc_si64: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: .cfi_def_cfa_offset 16 +; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; RV32IF-NEXT: .cfi_offset ra, -4 +; RV32IF-NEXT: fcvt.s.h fa0, fa0 +; RV32IF-NEXT: call truncf@plt +; RV32IF-NEXT: fcvt.h.s fa0, fa0 +; RV32IF-NEXT: call __fixhfdi@plt +; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_trunc_si64: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.h a0, fa0, rtz +; RV64IF-NEXT: ret + %a = call half @llvm.trunc.f16(half %x) + %b = fptosi half %a to i64 + ret i64 %b +} + +define zeroext i8 @test_trunc_ui8(half %x) { +; RV32IF-LABEL: test_trunc_ui8: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.h a0, fa0, rtz +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_trunc_ui8: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.h a0, fa0, rtz +; RV64IF-NEXT: ret + %a = call half @llvm.trunc.f16(half %x) + %b = fptoui half %a to i8 + ret i8 %b +} + +define zeroext i16 @test_trunc_ui16(half %x) { +; RV32IF-LABEL: test_trunc_ui16: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.h a0, fa0, rtz +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_trunc_ui16: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.h a0, fa0, rtz +; RV64IF-NEXT: ret + %a = call half @llvm.trunc.f16(half %x) + %b = fptoui half %a to i16 + ret i16 %b +} + +define signext i32 @test_trunc_ui32(half %x) { +; RV32IF-LABEL: test_trunc_ui32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.h a0, fa0, rtz +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_trunc_ui32: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.wu.h a0, fa0, rtz +; RV64IF-NEXT: ret + %a = call half @llvm.trunc.f16(half %x) + %b = fptoui half %a to i32 + ret i32 %b +} + +define i64 @test_trunc_ui64(half %x) { +; RV32IF-LABEL: test_trunc_ui64: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: .cfi_def_cfa_offset 16 +; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; RV32IF-NEXT: .cfi_offset ra, -4 +; RV32IF-NEXT: fcvt.s.h fa0, fa0 +; RV32IF-NEXT: call truncf@plt +; RV32IF-NEXT: fcvt.h.s fa0, fa0 +; RV32IF-NEXT: call __fixunshfdi@plt +; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_trunc_ui64: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.h a0, fa0, rtz +; RV64IF-NEXT: ret + %a = call half @llvm.trunc.f16(half %x) + %b = fptoui half %a to i64 + ret i64 %b +} + +define signext i8 @test_round_si8(half %x) { +; RV32IF-LABEL: test_round_si8: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.h a0, fa0, rmm +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_round_si8: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.h a0, fa0, rmm +; RV64IF-NEXT: ret + %a = call half @llvm.round.f16(half %x) + %b = fptosi half %a to i8 + ret i8 %b +} + +define signext i16 @test_round_si16(half %x) { +; RV32IF-LABEL: test_round_si16: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.h a0, fa0, rmm +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_round_si16: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.h a0, fa0, rmm +; RV64IF-NEXT: ret + %a = call half @llvm.round.f16(half %x) + %b = fptosi half %a to i16 + ret i16 %b +} + +define signext i32 @test_round_si32(half %x) { +; RV32IF-LABEL: test_round_si32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.h a0, fa0, rmm +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_round_si32: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.w.h a0, fa0, rmm +; RV64IF-NEXT: ret + %a = call half @llvm.round.f16(half %x) + %b = fptosi half %a to i32 + ret i32 %b +} + +define i64 @test_round_si64(half %x) { +; RV32IF-LABEL: test_round_si64: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: .cfi_def_cfa_offset 16 +; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; RV32IF-NEXT: .cfi_offset ra, -4 +; RV32IF-NEXT: fcvt.s.h fa0, fa0 +; RV32IF-NEXT: call roundf@plt +; RV32IF-NEXT: fcvt.h.s fa0, fa0 +; RV32IF-NEXT: call __fixhfdi@plt +; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_round_si64: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.h a0, fa0, rmm +; RV64IF-NEXT: ret + %a = call half @llvm.round.f16(half %x) + %b = fptosi half %a to i64 + ret i64 %b +} + +define zeroext i8 @test_round_ui8(half %x) { +; RV32IF-LABEL: test_round_ui8: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.h a0, fa0, rmm +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_round_ui8: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.h a0, fa0, rmm +; RV64IF-NEXT: ret + %a = call half @llvm.round.f16(half %x) + %b = fptoui half %a to i8 + ret i8 %b +} + +define zeroext i16 @test_round_ui16(half %x) { +; RV32IF-LABEL: test_round_ui16: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.h a0, fa0, rmm +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_round_ui16: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.h a0, fa0, rmm +; RV64IF-NEXT: ret + %a = call half @llvm.round.f16(half %x) + %b = fptoui half %a to i16 + ret i16 %b +} + +define signext i32 @test_round_ui32(half %x) { +; RV32IF-LABEL: test_round_ui32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.h a0, fa0, rmm +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_round_ui32: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.wu.h a0, fa0, rmm +; RV64IF-NEXT: ret + %a = call half @llvm.round.f16(half %x) + %b = fptoui half %a to i32 + ret i32 %b +} + +define i64 @test_round_ui64(half %x) { +; RV32IF-LABEL: test_round_ui64: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: .cfi_def_cfa_offset 16 +; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; RV32IF-NEXT: .cfi_offset ra, -4 +; RV32IF-NEXT: fcvt.s.h fa0, fa0 +; RV32IF-NEXT: call roundf@plt +; RV32IF-NEXT: fcvt.h.s fa0, fa0 +; RV32IF-NEXT: call __fixunshfdi@plt +; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_round_ui64: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.h a0, fa0, rmm +; RV64IF-NEXT: ret + %a = call half @llvm.round.f16(half %x) + %b = fptoui half %a to i64 + ret i64 %b +} + +define signext i8 @test_roundeven_si8(half %x) { +; RV32IF-LABEL: test_roundeven_si8: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.h a0, fa0, rne +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_roundeven_si8: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.h a0, fa0, rne +; RV64IF-NEXT: ret + %a = call half @llvm.roundeven.f16(half %x) + %b = fptosi half %a to i8 + ret i8 %b +} + +define signext i16 @test_roundeven_si16(half %x) { +; RV32IF-LABEL: test_roundeven_si16: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.h a0, fa0, rne +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_roundeven_si16: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.h a0, fa0, rne +; RV64IF-NEXT: ret + %a = call half @llvm.roundeven.f16(half %x) + %b = fptosi half %a to i16 + ret i16 %b +} + +define signext i32 @test_roundeven_si32(half %x) { +; RV32IF-LABEL: test_roundeven_si32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.w.h a0, fa0, rne +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_roundeven_si32: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.w.h a0, fa0, rne +; RV64IF-NEXT: ret + %a = call half @llvm.roundeven.f16(half %x) + %b = fptosi half %a to i32 + ret i32 %b +} + +define i64 @test_roundeven_si64(half %x) { +; RV32IF-LABEL: test_roundeven_si64: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: .cfi_def_cfa_offset 16 +; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; RV32IF-NEXT: .cfi_offset ra, -4 +; RV32IF-NEXT: fcvt.s.h fa0, fa0 +; RV32IF-NEXT: call roundevenf@plt +; RV32IF-NEXT: fcvt.h.s fa0, fa0 +; RV32IF-NEXT: call __fixhfdi@plt +; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_roundeven_si64: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.l.h a0, fa0, rne +; RV64IF-NEXT: ret + %a = call half @llvm.roundeven.f16(half %x) + %b = fptosi half %a to i64 + ret i64 %b +} + +define zeroext i8 @test_roundeven_ui8(half %x) { +; RV32IF-LABEL: test_roundeven_ui8: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.h a0, fa0, rne +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_roundeven_ui8: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.h a0, fa0, rne +; RV64IF-NEXT: ret + %a = call half @llvm.roundeven.f16(half %x) + %b = fptoui half %a to i8 + ret i8 %b +} + +define zeroext i16 @test_roundeven_ui16(half %x) { +; RV32IF-LABEL: test_roundeven_ui16: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.h a0, fa0, rne +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_roundeven_ui16: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.h a0, fa0, rne +; RV64IF-NEXT: ret + %a = call half @llvm.roundeven.f16(half %x) + %b = fptoui half %a to i16 + ret i16 %b +} + +define signext i32 @test_roundeven_ui32(half %x) { +; RV32IF-LABEL: test_roundeven_ui32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fcvt.wu.h a0, fa0, rne +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_roundeven_ui32: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.wu.h a0, fa0, rne +; RV64IF-NEXT: ret + %a = call half @llvm.roundeven.f16(half %x) + %b = fptoui half %a to i32 + ret i32 %b +} + +define i64 @test_roundeven_ui64(half %x) { +; RV32IF-LABEL: test_roundeven_ui64: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: .cfi_def_cfa_offset 16 +; RV32IF-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; RV32IF-NEXT: .cfi_offset ra, -4 +; RV32IF-NEXT: fcvt.s.h fa0, fa0 +; RV32IF-NEXT: call roundevenf@plt +; RV32IF-NEXT: fcvt.h.s fa0, fa0 +; RV32IF-NEXT: call __fixunshfdi@plt +; RV32IF-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret +; +; RV64IF-LABEL: test_roundeven_ui64: +; RV64IF: # %bb.0: +; RV64IF-NEXT: fcvt.lu.h a0, fa0, rne +; RV64IF-NEXT: ret + %a = call half @llvm.roundeven.f16(half %x) + %b = fptoui half %a to i64 + ret i64 %b +} + +declare half @llvm.floor.f16(half) +declare half @llvm.ceil.f16(half) +declare half @llvm.trunc.f16(half) +declare half @llvm.round.f16(half) +declare half @llvm.roundeven.f16(half)