Index: include/llvm/CodeGen/TargetLowering.h =================================================================== --- include/llvm/CodeGen/TargetLowering.h +++ include/llvm/CodeGen/TargetLowering.h @@ -187,13 +187,14 @@ bool IsReturned : 1; bool IsSwiftSelf : 1; bool IsSwiftError : 1; + bool IsCastFromFloat : 1; uint16_t Alignment = 0; Type *ByValType = nullptr; ArgListEntry() : IsSExt(false), IsZExt(false), IsInReg(false), IsSRet(false), IsNest(false), IsByVal(false), IsInAlloca(false), IsReturned(false), - IsSwiftSelf(false), IsSwiftError(false) {} + IsSwiftSelf(false), IsSwiftError(false), IsCastFromFloat(false) {} void setAttributes(const CallBase *Call, unsigned ArgIdx); @@ -1828,6 +1829,11 @@ return IsSigned; } + /// Returns true if arguments should be extended in lib calls. + virtual bool shouldExtendTypeInLibCall(EVT Type, bool IsCastFromFloat) const { + return true; + } + /// Returns how the given (atomic) load should be expanded by the /// IR-level AtomicExpand pass. virtual AtomicExpansionKind shouldExpandAtomicLoadInIR(LoadInst *LI) const { @@ -3404,6 +3410,7 @@ bool IsReturnValueUsed : 1; bool IsConvergent : 1; bool IsPatchPoint : 1; + bool IsCastFromFloat : 1; // IsTailCall should be modified by implementations of // TargetLowering::LowerCall that perform tail call conversions. @@ -3427,7 +3434,7 @@ CallLoweringInfo(SelectionDAG &DAG) : RetSExt(false), RetZExt(false), IsVarArg(false), IsInReg(false), DoesNotReturn(false), IsReturnValueUsed(true), IsConvergent(false), - IsPatchPoint(false), DAG(DAG) {} + IsPatchPoint(false), IsCastFromFloat(false), DAG(DAG) {} CallLoweringInfo &setDebugLoc(const SDLoc &dl) { DL = dl; Index: lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp =================================================================== --- lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp +++ lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp @@ -123,6 +123,39 @@ return false; } +TargetLowering::makeLibCallOptions +DAGTypeLegalizer::SetIsCastFromFloatForSoftenedFloat(SDNode *N) { + LLVM_DEBUG(dbgs() << "Set IsCastFromFloat flag for Soften float : "; + N->dump(&DAG); dbgs() << "\n"); + TargetLowering::makeLibCallOptions CallOptions(DAG); + switch (N->getOpcode()) { + default: + break; + case ISD::FADD: + case ISD::FSUB: + case ISD::FMUL: + case ISD::FDIV: + case ISD::FMA: + case ISD::FSQRT: + case ISD::FMINNUM: + case ISD::FMAXNUM: + CallOptions.Entry.IsCastFromFloat = true; + CallOptions.CLI.IsCastFromFloat = true; + break; + case ISD::FP_TO_SINT: + case ISD::FP_TO_UINT: + CallOptions.Entry.IsCastFromFloat = true; + CallOptions.CLI.IsCastFromFloat = false; + break; + case ISD::SINT_TO_FP: + case ISD::UINT_TO_FP: + CallOptions.Entry.IsCastFromFloat = false; + CallOptions.CLI.IsCastFromFloat = true; + break; + } + return CallOptions; +} + SDValue DAGTypeLegalizer::SoftenFloatRes_BITCAST(SDNode *N, unsigned ResNo) { if (isLegalInHWReg(N->getValueType(ResNo))) return SDValue(N, ResNo); @@ -200,7 +233,8 @@ EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); SDValue Ops[2] = { GetSoftenedFloat(N->getOperand(0)), GetSoftenedFloat(N->getOperand(1)) }; - TargetLowering::makeLibCallOptions CallOptions(DAG); + TargetLowering::makeLibCallOptions CallOptions = + SetIsCastFromFloatForSoftenedFloat(N); return TLI.makeLibCall(DAG, GetFPLibCall(N->getValueType(0), RTLIB::FMIN_F32, RTLIB::FMIN_F64, @@ -214,7 +248,8 @@ EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); SDValue Ops[2] = { GetSoftenedFloat(N->getOperand(0)), GetSoftenedFloat(N->getOperand(1)) }; - TargetLowering::makeLibCallOptions CallOptions(DAG); + TargetLowering::makeLibCallOptions CallOptions = + SetIsCastFromFloatForSoftenedFloat(N); return TLI.makeLibCall(DAG, GetFPLibCall(N->getValueType(0), RTLIB::FMAX_F32, RTLIB::FMAX_F64, @@ -228,7 +263,8 @@ EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); SDValue Ops[2] = { GetSoftenedFloat(N->getOperand(0)), GetSoftenedFloat(N->getOperand(1)) }; - TargetLowering::makeLibCallOptions CallOptions(DAG); + TargetLowering::makeLibCallOptions CallOptions = + SetIsCastFromFloatForSoftenedFloat(N); return TLI.makeLibCall(DAG, GetFPLibCall(N->getValueType(0), RTLIB::ADD_F32, RTLIB::ADD_F64, @@ -319,7 +355,8 @@ EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); SDValue Ops[2] = { GetSoftenedFloat(N->getOperand(0)), GetSoftenedFloat(N->getOperand(1)) }; - TargetLowering::makeLibCallOptions CallOptions(DAG); + TargetLowering::makeLibCallOptions CallOptions = + SetIsCastFromFloatForSoftenedFloat(N); return TLI.makeLibCall(DAG, GetFPLibCall(N->getValueType(0), RTLIB::DIV_F32, RTLIB::DIV_F64, @@ -412,7 +449,8 @@ SDValue Ops[3] = { GetSoftenedFloat(N->getOperand(0)), GetSoftenedFloat(N->getOperand(1)), GetSoftenedFloat(N->getOperand(2)) }; - TargetLowering::makeLibCallOptions CallOptions(DAG); + TargetLowering::makeLibCallOptions CallOptions = + SetIsCastFromFloatForSoftenedFloat(N); return TLI.makeLibCall(DAG, GetFPLibCall(N->getValueType(0), RTLIB::FMA_F32, RTLIB::FMA_F64, @@ -426,7 +464,8 @@ EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); SDValue Ops[2] = { GetSoftenedFloat(N->getOperand(0)), GetSoftenedFloat(N->getOperand(1)) }; - TargetLowering::makeLibCallOptions CallOptions(DAG); + TargetLowering::makeLibCallOptions CallOptions = + SetIsCastFromFloatForSoftenedFloat(N); return TLI.makeLibCall(DAG, GetFPLibCall(N->getValueType(0), RTLIB::MUL_F32, RTLIB::MUL_F64, @@ -622,7 +661,8 @@ SDValue DAGTypeLegalizer::SoftenFloatRes_FSQRT(SDNode *N) { EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); SDValue Op = GetSoftenedFloat(N->getOperand(0)); - TargetLowering::makeLibCallOptions CallOptions(DAG); + TargetLowering::makeLibCallOptions CallOptions = + SetIsCastFromFloatForSoftenedFloat(N); return TLI.makeLibCall(DAG, GetFPLibCall(N->getValueType(0), RTLIB::SQRT_F32, RTLIB::SQRT_F64, @@ -636,7 +676,8 @@ EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), N->getValueType(0)); SDValue Ops[2] = { GetSoftenedFloat(N->getOperand(0)), GetSoftenedFloat(N->getOperand(1)) }; - TargetLowering::makeLibCallOptions CallOptions(DAG); + TargetLowering::makeLibCallOptions CallOptions = + SetIsCastFromFloatForSoftenedFloat(N); return TLI.makeLibCall(DAG, GetFPLibCall(N->getValueType(0), RTLIB::SUB_F32, RTLIB::SUB_F64, @@ -764,7 +805,8 @@ // Sign/zero extend the argument if the libcall takes a larger type. SDValue Op = DAG.getNode(Signed ? ISD::SIGN_EXTEND : ISD::ZERO_EXTEND, dl, NVT, N->getOperand(0)); - TargetLowering::makeLibCallOptions CallOptions(DAG); + TargetLowering::makeLibCallOptions CallOptions = + SetIsCastFromFloatForSoftenedFloat(N); CallOptions.Entry.IsSExt = CallOptions.CLI.RetSExt = Signed; return TLI.makeLibCall(DAG, LC, TLI.getTypeToTransformTo(*DAG.getContext(), RVT), @@ -994,7 +1036,8 @@ assert(LC != RTLIB::UNKNOWN_LIBCALL && "Unsupported FP_TO_XINT!"); SDValue Op = GetSoftenedFloat(N->getOperand(0)); - TargetLowering::makeLibCallOptions CallOptions(DAG); + TargetLowering::makeLibCallOptions CallOptions = + SetIsCastFromFloatForSoftenedFloat(N); SDValue Res = TLI.makeLibCall(DAG, LC, NVT, Op, CallOptions, dl).first; // Truncate the result if the libcall returns a larger type. Index: lib/CodeGen/SelectionDAG/LegalizeTypes.h =================================================================== --- lib/CodeGen/SelectionDAG/LegalizeTypes.h +++ lib/CodeGen/SelectionDAG/LegalizeTypes.h @@ -246,6 +246,9 @@ // Integer Promotion Support: LegalizeIntegerTypes.cpp //===--------------------------------------------------------------------===// + TargetLowering::makeLibCallOptions + SetIsCastFromFloatForSoftenedFloat(SDNode *N); + /// Given a processed operand Op which was promoted to a larger integer type, /// this returns the promoted value. The low bits of the promoted value /// corresponding to the original type are exactly equal to Op. Index: lib/CodeGen/SelectionDAG/TargetLowering.cpp =================================================================== --- lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -128,12 +128,18 @@ Args.reserve(Ops.size()); TargetLowering::ArgListEntry Entry; + bool shouldExt; for (SDValue Op : Ops) { Entry.Node = Op; Entry.Ty = Entry.Node.getValueType().getTypeForEVT(*DAG.getContext()); Entry.IsSExt = shouldSignExtendTypeInLibCall(Op.getValueType(), CallOptions.Entry.IsSExt); Entry.IsZExt = !Entry.IsSExt; + + shouldExt = shouldExtendTypeInLibCall(Op.getValueType(), + CallOptions.Entry.IsCastFromFloat); + Entry.IsSExt = Entry.IsSExt && shouldExt; + Entry.IsZExt = Entry.IsZExt && shouldExt; Args.push_back(Entry); } @@ -143,9 +149,15 @@ getPointerTy(DAG.getDataLayout())); Type *RetTy = RetVT.getTypeForEVT(*DAG.getContext()); - TargetLowering::CallLoweringInfo CLI(DAG); bool signExtend = shouldSignExtendTypeInLibCall(RetVT, CallOptions.CLI.RetSExt); + bool zeroExtend = !signExtend; + + shouldExt = shouldExtendTypeInLibCall(RetVT, CallOptions.CLI.IsCastFromFloat); + signExtend = signExtend && shouldExt; + zeroExtend = zeroExtend && shouldExt; + + TargetLowering::CallLoweringInfo CLI(DAG); CLI.setDebugLoc(dl) .setChain(DAG.getEntryNode()) .setLibCallee(getLibcallCallingConv(LC), RetTy, Callee, std::move(Args)) @@ -153,7 +165,7 @@ .setDiscardResult(!CallOptions.CLI.IsReturnValueUsed) .setIsPostTypeLegalization(CallOptions.CLI.IsPostTypeLegalization) .setSExtResult(signExtend) - .setZExtResult(!signExtend); + .setZExtResult(zeroExtend); return LowerCallTo(CLI); } @@ -367,6 +379,7 @@ EVT RetVT = getCmpLibcallReturnType(); SDValue Ops[2] = {NewLHS, NewRHS}; TargetLowering::makeLibCallOptions CallOptions(DAG); + CallOptions.Entry.IsCastFromFloat = true; NewLHS = makeLibCall(DAG, LC1, RetVT, Ops, CallOptions, dl).first; NewRHS = DAG.getConstant(0, dl, RetVT); Index: lib/Target/RISCV/RISCVISelLowering.h =================================================================== --- lib/Target/RISCV/RISCVISelLowering.h +++ lib/Target/RISCV/RISCVISelLowering.h @@ -141,6 +141,8 @@ unsigned getExceptionSelectorRegister(const Constant *PersonalityFn) const override; + bool shouldExtendTypeInLibCall(EVT Type, bool IsCastFromFloat) const override; + private: void analyzeInputArgs(MachineFunction &MF, CCState &CCInfo, const SmallVectorImpl &Ins, Index: lib/Target/RISCV/RISCVISelLowering.cpp =================================================================== --- lib/Target/RISCV/RISCVISelLowering.cpp +++ lib/Target/RISCV/RISCVISelLowering.cpp @@ -2643,3 +2643,14 @@ const Constant *PersonalityFn) const { return RISCV::X11; } + +bool RISCVTargetLowering::shouldExtendTypeInLibCall( + EVT Type, bool IsCastFromFloat) const { + // Return false to suppress the unnecessary extensions if the LibCall + // arguments or return value is cast from floating for LP64 ABI. + RISCVABI::ABI ABI = Subtarget.getTargetABI(); + if ((ABI == RISCVABI::ABI_LP64) && (Type == MVT::i32) && IsCastFromFloat) + return false; + + return true; +} Index: test/CodeGen/RISCV/calling-conv-lp64.ll =================================================================== --- test/CodeGen/RISCV/calling-conv-lp64.ll +++ test/CodeGen/RISCV/calling-conv-lp64.ll @@ -21,8 +21,7 @@ ; RV64I-FPELIM-NEXT: sd ra, 8(sp) ; RV64I-FPELIM-NEXT: sd s0, 0(sp) ; RV64I-FPELIM-NEXT: mv s0, a0 -; RV64I-FPELIM-NEXT: slli a0, a1, 32 -; RV64I-FPELIM-NEXT: srli a0, a0, 32 +; RV64I-FPELIM-NEXT: mv a0, a1 ; RV64I-FPELIM-NEXT: call __fixsfdi ; RV64I-FPELIM-NEXT: add a0, s0, a0 ; RV64I-FPELIM-NEXT: ld s0, 0(sp) @@ -38,8 +37,7 @@ ; RV64I-WITHFP-NEXT: sd s1, 8(sp) ; RV64I-WITHFP-NEXT: addi s0, sp, 32 ; RV64I-WITHFP-NEXT: mv s1, a0 -; RV64I-WITHFP-NEXT: slli a0, a1, 32 -; RV64I-WITHFP-NEXT: srli a0, a0, 32 +; RV64I-WITHFP-NEXT: mv a0, a1 ; RV64I-WITHFP-NEXT: call __fixsfdi ; RV64I-WITHFP-NEXT: add a0, s1, a0 ; RV64I-WITHFP-NEXT: ld s1, 8(sp) Index: test/CodeGen/RISCV/float-arith.ll =================================================================== --- test/CodeGen/RISCV/float-arith.ll +++ test/CodeGen/RISCV/float-arith.ll @@ -3,6 +3,8 @@ ; 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 -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=RV64I %s ; These tests are each targeted at a particular RISC-V FPU instruction. Most ; other files in this folder exercise LLVM IR instructions that don't directly @@ -24,6 +26,15 @@ ; RV64IF-NEXT: fadd.s ft0, ft1, ft0 ; RV64IF-NEXT: fmv.x.w a0, ft0 ; RV64IF-NEXT: ret +; +; RV64I-LABEL: fadd_s: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: call __addsf3 +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret %1 = fadd float %a, %b ret float %1 } @@ -44,6 +55,15 @@ ; RV64IF-NEXT: fsub.s ft0, ft1, ft0 ; RV64IF-NEXT: fmv.x.w a0, ft0 ; RV64IF-NEXT: ret +; +; RV64I-LABEL: fsub_s: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: call __subsf3 +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret %1 = fsub float %a, %b ret float %1 } @@ -64,6 +84,15 @@ ; RV64IF-NEXT: fmul.s ft0, ft1, ft0 ; RV64IF-NEXT: fmv.x.w a0, ft0 ; RV64IF-NEXT: ret +; +; RV64I-LABEL: fmul_s: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: call __mulsf3 +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret %1 = fmul float %a, %b ret float %1 } @@ -84,6 +113,15 @@ ; RV64IF-NEXT: fdiv.s ft0, ft1, ft0 ; RV64IF-NEXT: fmv.x.w a0, ft0 ; RV64IF-NEXT: ret +; +; RV64I-LABEL: fdiv_s: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: call __divsf3 +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret %1 = fdiv float %a, %b ret float %1 } @@ -104,6 +142,15 @@ ; RV64IF-NEXT: fsqrt.s ft0, ft0 ; RV64IF-NEXT: fmv.x.w a0, ft0 ; RV64IF-NEXT: ret +; +; RV64I-LABEL: fsqrt_s: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: call sqrtf +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret %1 = call float @llvm.sqrt.f32(float %a) ret float %1 } @@ -126,6 +173,15 @@ ; RV64IF-NEXT: fsgnj.s ft0, ft1, ft0 ; RV64IF-NEXT: fmv.x.w a0, ft0 ; RV64IF-NEXT: ret +; +; RV64I-LABEL: fsgnj_s: +; RV64I: # %bb.0: +; RV64I-NEXT: lui a2, 524288 +; RV64I-NEXT: and a1, a1, a2 +; RV64I-NEXT: addiw a2, a2, -1 +; RV64I-NEXT: and a0, a0, a2 +; RV64I-NEXT: or a0, a0, a1 +; RV64I-NEXT: ret %1 = call float @llvm.copysign.f32(float %a, float %b) ret float %1 } @@ -148,6 +204,20 @@ ; RV64IF-NEXT: fneg.s ft1, ft0 ; RV64IF-NEXT: feq.s a0, ft0, ft1 ; RV64IF-NEXT: ret +; +; RV64I-LABEL: fneg_s: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: mv a1, a0 +; RV64I-NEXT: call __addsf3 +; RV64I-NEXT: lui a1, 524288 +; RV64I-NEXT: xor a1, a0, a1 +; RV64I-NEXT: call __eqsf2 +; RV64I-NEXT: seqz a0, a0 +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret %1 = fadd float %a, %a %2 = fneg float %1 %3 = fcmp oeq float %1, %2 @@ -175,6 +245,24 @@ ; RV64IF-NEXT: fsgnjn.s ft0, ft1, ft0 ; RV64IF-NEXT: fmv.x.w a0, ft0 ; RV64IF-NEXT: ret +; +; RV64I-LABEL: fsgnjn_s: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: sd s0, 0(sp) +; RV64I-NEXT: mv s0, a0 +; RV64I-NEXT: call __addsf3 +; RV64I-NEXT: lui a1, 524288 +; RV64I-NEXT: addiw a2, a1, -1 +; RV64I-NEXT: and a2, s0, a2 +; RV64I-NEXT: not a0, a0 +; RV64I-NEXT: and a0, a0, a1 +; RV64I-NEXT: or a0, a2, a0 +; RV64I-NEXT: ld s0, 0(sp) +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret %1 = fadd float %a, %b %2 = fneg float %1 %3 = call float @llvm.copysign.f32(float %a, float %2) @@ -205,6 +293,20 @@ ; RV64IF-NEXT: fadd.s ft0, ft1, ft0 ; RV64IF-NEXT: fmv.x.w a0, ft0 ; RV64IF-NEXT: ret +; +; RV64I-LABEL: fabs_s: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: call __addsf3 +; RV64I-NEXT: mv a1, a0 +; RV64I-NEXT: lui a0, 524288 +; RV64I-NEXT: addiw a0, a0, -1 +; RV64I-NEXT: and a0, a1, a0 +; RV64I-NEXT: call __addsf3 +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret %1 = fadd float %a, %b %2 = call float @llvm.fabs.f32(float %1) %3 = fadd float %2, %1 @@ -229,6 +331,15 @@ ; RV64IF-NEXT: fmin.s ft0, ft1, ft0 ; RV64IF-NEXT: fmv.x.w a0, ft0 ; RV64IF-NEXT: ret +; +; RV64I-LABEL: fmin_s: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: call fminf +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret %1 = call float @llvm.minnum.f32(float %a, float %b) ret float %1 } @@ -251,6 +362,15 @@ ; RV64IF-NEXT: fmax.s ft0, ft1, ft0 ; RV64IF-NEXT: fmv.x.w a0, ft0 ; RV64IF-NEXT: ret +; +; RV64I-LABEL: fmax_s: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: call fmaxf +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret %1 = call float @llvm.maxnum.f32(float %a, float %b) ret float %1 } @@ -269,6 +389,16 @@ ; RV64IF-NEXT: fmv.w.x ft1, a0 ; RV64IF-NEXT: feq.s a0, ft1, ft0 ; RV64IF-NEXT: ret +; +; RV64I-LABEL: feq_s: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: call __eqsf2 +; RV64I-NEXT: seqz a0, a0 +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret %1 = fcmp oeq float %a, %b %2 = zext i1 %1 to i32 ret i32 %2 @@ -288,6 +418,17 @@ ; RV64IF-NEXT: fmv.w.x ft1, a0 ; RV64IF-NEXT: flt.s a0, ft1, ft0 ; RV64IF-NEXT: ret +; +; RV64I-LABEL: flt_s: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: call __ltsf2 +; RV64I-NEXT: sext.w a0, a0 +; RV64I-NEXT: slti a0, a0, 0 +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret %1 = fcmp olt float %a, %b %2 = zext i1 %1 to i32 ret i32 %2 @@ -307,6 +448,17 @@ ; RV64IF-NEXT: fmv.w.x ft1, a0 ; RV64IF-NEXT: fle.s a0, ft1, ft0 ; RV64IF-NEXT: ret +; +; RV64I-LABEL: fle_s: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: call __lesf2 +; RV64I-NEXT: sext.w a0, a0 +; RV64I-NEXT: slti a0, a0, 1 +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret %1 = fcmp ole float %a, %b %2 = zext i1 %1 to i32 ret i32 %2 @@ -332,6 +484,15 @@ ; RV64IF-NEXT: fmadd.s ft0, ft2, ft1, ft0 ; RV64IF-NEXT: fmv.x.w a0, ft0 ; RV64IF-NEXT: ret +; +; RV64I-LABEL: fmadd_s: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: call fmaf +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret %1 = call float @llvm.fma.f32(float %a, float %b, float %c) ret float %1 } @@ -362,6 +523,28 @@ ; RV64IF-NEXT: fmsub.s ft0, ft2, ft1, ft0 ; RV64IF-NEXT: fmv.x.w a0, ft0 ; RV64IF-NEXT: ret +; +; RV64I-LABEL: fmsub_s: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -32 +; RV64I-NEXT: sd ra, 24(sp) +; RV64I-NEXT: sd s0, 16(sp) +; RV64I-NEXT: sd s1, 8(sp) +; RV64I-NEXT: mv s0, a1 +; RV64I-NEXT: mv s1, a0 +; RV64I-NEXT: mv a0, a2 +; RV64I-NEXT: mv a1, zero +; RV64I-NEXT: call __addsf3 +; RV64I-NEXT: lui a1, 524288 +; RV64I-NEXT: xor a2, a0, a1 +; RV64I-NEXT: mv a0, s1 +; RV64I-NEXT: mv a1, s0 +; RV64I-NEXT: call fmaf +; RV64I-NEXT: ld s1, 8(sp) +; RV64I-NEXT: ld s0, 16(sp) +; RV64I-NEXT: ld ra, 24(sp) +; RV64I-NEXT: addi sp, sp, 32 +; RV64I-NEXT: ret %c_ = fadd float 0.0, %c ; avoid negation using xor %negc = fsub float -0.0, %c_ %1 = call float @llvm.fma.f32(float %a, float %b, float %negc) @@ -396,6 +579,34 @@ ; RV64IF-NEXT: fnmadd.s ft0, ft1, ft2, ft0 ; RV64IF-NEXT: fmv.x.w a0, ft0 ; RV64IF-NEXT: ret +; +; RV64I-LABEL: fnmadd_s: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -32 +; RV64I-NEXT: sd ra, 24(sp) +; RV64I-NEXT: sd s0, 16(sp) +; RV64I-NEXT: sd s1, 8(sp) +; RV64I-NEXT: sd s2, 0(sp) +; RV64I-NEXT: mv s0, a2 +; RV64I-NEXT: mv s2, a1 +; RV64I-NEXT: mv a1, zero +; RV64I-NEXT: call __addsf3 +; RV64I-NEXT: mv s1, a0 +; RV64I-NEXT: mv a0, s0 +; RV64I-NEXT: mv a1, zero +; RV64I-NEXT: call __addsf3 +; RV64I-NEXT: lui a2, 524288 +; RV64I-NEXT: xor a1, s1, a2 +; RV64I-NEXT: xor a2, a0, a2 +; RV64I-NEXT: mv a0, a1 +; RV64I-NEXT: mv a1, s2 +; RV64I-NEXT: call fmaf +; RV64I-NEXT: ld s2, 0(sp) +; RV64I-NEXT: ld s1, 8(sp) +; RV64I-NEXT: ld s0, 16(sp) +; RV64I-NEXT: ld ra, 24(sp) +; RV64I-NEXT: addi sp, sp, 32 +; RV64I-NEXT: ret %a_ = fadd float 0.0, %a %c_ = fadd float 0.0, %c %nega = fsub float -0.0, %a_ @@ -430,6 +641,27 @@ ; RV64IF-NEXT: fnmsub.s ft0, ft0, ft2, ft1 ; RV64IF-NEXT: fmv.x.w a0, ft0 ; RV64IF-NEXT: ret +; +; RV64I-LABEL: fnmsub_s: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -32 +; RV64I-NEXT: sd ra, 24(sp) +; RV64I-NEXT: sd s0, 16(sp) +; RV64I-NEXT: sd s1, 8(sp) +; RV64I-NEXT: mv s0, a2 +; RV64I-NEXT: mv s1, a1 +; RV64I-NEXT: mv a1, zero +; RV64I-NEXT: call __addsf3 +; RV64I-NEXT: lui a1, 524288 +; RV64I-NEXT: xor a0, a0, a1 +; RV64I-NEXT: mv a1, s1 +; RV64I-NEXT: mv a2, s0 +; RV64I-NEXT: call fmaf +; RV64I-NEXT: ld s1, 8(sp) +; RV64I-NEXT: ld s0, 16(sp) +; RV64I-NEXT: ld ra, 24(sp) +; RV64I-NEXT: addi sp, sp, 32 +; RV64I-NEXT: ret %a_ = fadd float 0.0, %a %nega = fsub float -0.0, %a_ %1 = call float @llvm.fma.f32(float %nega, float %b, float %c) Index: test/CodeGen/RISCV/float-convert.ll =================================================================== --- test/CodeGen/RISCV/float-convert.ll +++ test/CodeGen/RISCV/float-convert.ll @@ -3,6 +3,8 @@ ; 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 -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=RV64I %s ; For RV64F, fcvt.l.s is semantically equivalent to fcvt.w.s in this case ; because fptosi will produce poison if the result doesn't fit into an i32. @@ -18,6 +20,15 @@ ; RV64IF-NEXT: fmv.w.x ft0, a0 ; RV64IF-NEXT: fcvt.l.s a0, ft0, rtz ; RV64IF-NEXT: ret +; +; RV64I-LABEL: fcvt_w_s: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: call __fixsfdi +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret %1 = fptosi float %a to i32 ret i32 %1 } @@ -36,6 +47,15 @@ ; RV64IF-NEXT: fmv.w.x ft0, a0 ; RV64IF-NEXT: fcvt.lu.s a0, ft0, rtz ; RV64IF-NEXT: ret +; +; RV64I-LABEL: fcvt_wu_s: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: call __fixunssfdi +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret %1 = fptoui float %a to i32 ret i32 %1 } @@ -56,6 +76,15 @@ ; RV64IF-NEXT: fadd.s ft0, ft1, ft0 ; RV64IF-NEXT: fmv.x.w a0, ft0 ; RV64IF-NEXT: ret +; +; RV64I-LABEL: fmv_x_w: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: call __addsf3 +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret ; Ensure fmv.x.w is generated even for a soft float calling convention %1 = fadd float %a, %b %2 = bitcast float %1 to i32 @@ -74,6 +103,16 @@ ; RV64IF-NEXT: fcvt.s.w ft0, a0 ; RV64IF-NEXT: fmv.x.w a0, ft0 ; RV64IF-NEXT: ret +; +; RV64I-LABEL: fcvt_s_w: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: sext.w a0, a0 +; RV64I-NEXT: call __floatsisf +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret %1 = sitofp i32 %a to float ret float %1 } @@ -90,6 +129,17 @@ ; RV64IF-NEXT: fcvt.s.wu ft0, a0 ; RV64IF-NEXT: fmv.x.w a0, ft0 ; RV64IF-NEXT: ret +; +; RV64I-LABEL: fcvt_s_wu: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: slli a0, a0, 32 +; RV64I-NEXT: srli a0, a0, 32 +; RV64I-NEXT: call __floatunsisf +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret %1 = uitofp i32 %a to float ret float %1 } @@ -110,6 +160,15 @@ ; RV64IF-NEXT: fadd.s ft0, ft1, ft0 ; RV64IF-NEXT: fmv.x.w a0, ft0 ; RV64IF-NEXT: ret +; +; RV64I-LABEL: fmv_w_x: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: call __addsf3 +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret ; Ensure fmv.w.x is generated even for a soft float calling convention %1 = bitcast i32 %a to float %2 = bitcast i32 %b to float @@ -132,6 +191,15 @@ ; RV64IF-NEXT: fmv.w.x ft0, a0 ; RV64IF-NEXT: fcvt.l.s a0, ft0, rtz ; RV64IF-NEXT: ret +; +; RV64I-LABEL: fcvt_l_s: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: call __fixsfdi +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret %1 = fptosi float %a to i64 ret i64 %1 } @@ -151,6 +219,15 @@ ; RV64IF-NEXT: fmv.w.x ft0, a0 ; RV64IF-NEXT: fcvt.lu.s a0, ft0, rtz ; RV64IF-NEXT: ret +; +; RV64I-LABEL: fcvt_lu_s: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: call __fixunssfdi +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret %1 = fptoui float %a to i64 ret i64 %1 } @@ -170,6 +247,15 @@ ; RV64IF-NEXT: fcvt.s.l ft0, a0 ; RV64IF-NEXT: fmv.x.w a0, ft0 ; RV64IF-NEXT: ret +; +; RV64I-LABEL: fcvt_s_l: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: call __floatdisf +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret %1 = sitofp i64 %a to float ret float %1 } @@ -189,6 +275,15 @@ ; RV64IF-NEXT: fcvt.s.lu ft0, a0 ; RV64IF-NEXT: fmv.x.w a0, ft0 ; RV64IF-NEXT: ret +; +; RV64I-LABEL: fcvt_s_lu: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: call __floatundisf +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret %1 = uitofp i64 %a to float ret float %1 } Index: test/CodeGen/RISCV/float-fcmp.ll =================================================================== --- test/CodeGen/RISCV/float-fcmp.ll +++ test/CodeGen/RISCV/float-fcmp.ll @@ -3,6 +3,8 @@ ; 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 -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=RV64I %s define i32 @fcmp_false(float %a, float %b) nounwind { ; RV32IF-LABEL: fcmp_false: @@ -14,6 +16,11 @@ ; RV64IF: # %bb.0: ; RV64IF-NEXT: mv a0, zero ; RV64IF-NEXT: ret +; +; RV64I-LABEL: fcmp_false: +; RV64I: # %bb.0: +; RV64I-NEXT: mv a0, zero +; RV64I-NEXT: ret %1 = fcmp false float %a, %b %2 = zext i1 %1 to i32 ret i32 %2 @@ -33,6 +40,16 @@ ; RV64IF-NEXT: fmv.w.x ft1, a0 ; RV64IF-NEXT: feq.s a0, ft1, ft0 ; RV64IF-NEXT: ret +; +; RV64I-LABEL: fcmp_oeq: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: call __eqsf2 +; RV64I-NEXT: seqz a0, a0 +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret %1 = fcmp oeq float %a, %b %2 = zext i1 %1 to i32 ret i32 %2 @@ -52,6 +69,17 @@ ; RV64IF-NEXT: fmv.w.x ft1, a1 ; RV64IF-NEXT: flt.s a0, ft1, ft0 ; RV64IF-NEXT: ret +; +; RV64I-LABEL: fcmp_ogt: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: call __gtsf2 +; RV64I-NEXT: sext.w a0, a0 +; RV64I-NEXT: sgtz a0, a0 +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret %1 = fcmp ogt float %a, %b %2 = zext i1 %1 to i32 ret i32 %2 @@ -71,6 +99,18 @@ ; RV64IF-NEXT: fmv.w.x ft1, a1 ; RV64IF-NEXT: fle.s a0, ft1, ft0 ; RV64IF-NEXT: ret +; +; RV64I-LABEL: fcmp_oge: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: call __gesf2 +; RV64I-NEXT: sext.w a0, a0 +; RV64I-NEXT: addi a1, zero, -1 +; RV64I-NEXT: slt a0, a1, a0 +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret %1 = fcmp oge float %a, %b %2 = zext i1 %1 to i32 ret i32 %2 @@ -90,6 +130,17 @@ ; RV64IF-NEXT: fmv.w.x ft1, a0 ; RV64IF-NEXT: flt.s a0, ft1, ft0 ; RV64IF-NEXT: ret +; +; RV64I-LABEL: fcmp_olt: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: call __ltsf2 +; RV64I-NEXT: sext.w a0, a0 +; RV64I-NEXT: slti a0, a0, 0 +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret %1 = fcmp olt float %a, %b %2 = zext i1 %1 to i32 ret i32 %2 @@ -109,6 +160,17 @@ ; RV64IF-NEXT: fmv.w.x ft1, a0 ; RV64IF-NEXT: fle.s a0, ft1, ft0 ; RV64IF-NEXT: ret +; +; RV64I-LABEL: fcmp_ole: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: call __lesf2 +; RV64I-NEXT: sext.w a0, a0 +; RV64I-NEXT: slti a0, a0, 1 +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret %1 = fcmp ole float %a, %b %2 = zext i1 %1 to i32 ret i32 %2 @@ -138,6 +200,31 @@ ; RV64IF-NEXT: not a1, a1 ; RV64IF-NEXT: and a0, a1, a0 ; RV64IF-NEXT: ret +; +; RV64I-LABEL: fcmp_one: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -32 +; RV64I-NEXT: sd ra, 24(sp) +; RV64I-NEXT: sd s0, 16(sp) +; RV64I-NEXT: sd s1, 8(sp) +; RV64I-NEXT: sd s2, 0(sp) +; RV64I-NEXT: mv s0, a1 +; RV64I-NEXT: mv s1, a0 +; RV64I-NEXT: call __gtsf2 +; RV64I-NEXT: sext.w a0, a0 +; RV64I-NEXT: sgtz s2, a0 +; RV64I-NEXT: mv a0, s1 +; RV64I-NEXT: mv a1, s0 +; RV64I-NEXT: call __ltsf2 +; RV64I-NEXT: sext.w a0, a0 +; RV64I-NEXT: slti a0, a0, 0 +; RV64I-NEXT: or a0, a0, s2 +; RV64I-NEXT: ld s2, 0(sp) +; RV64I-NEXT: ld s1, 8(sp) +; RV64I-NEXT: ld s0, 16(sp) +; RV64I-NEXT: ld ra, 24(sp) +; RV64I-NEXT: addi sp, sp, 32 +; RV64I-NEXT: ret %1 = fcmp one float %a, %b %2 = zext i1 %1 to i32 ret i32 %2 @@ -161,6 +248,16 @@ ; RV64IF-NEXT: feq.s a0, ft0, ft0 ; RV64IF-NEXT: and a0, a0, a1 ; RV64IF-NEXT: ret +; +; RV64I-LABEL: fcmp_ord: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: call __unordsf2 +; RV64I-NEXT: seqz a0, a0 +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret %1 = fcmp ord float %a, %b %2 = zext i1 %1 to i32 ret i32 %2 @@ -190,6 +287,29 @@ ; RV64IF-NEXT: seqz a1, a1 ; RV64IF-NEXT: or a0, a0, a1 ; RV64IF-NEXT: ret +; +; RV64I-LABEL: fcmp_ueq: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -32 +; RV64I-NEXT: sd ra, 24(sp) +; RV64I-NEXT: sd s0, 16(sp) +; RV64I-NEXT: sd s1, 8(sp) +; RV64I-NEXT: sd s2, 0(sp) +; RV64I-NEXT: mv s0, a1 +; RV64I-NEXT: mv s1, a0 +; RV64I-NEXT: call __eqsf2 +; RV64I-NEXT: seqz s2, a0 +; RV64I-NEXT: mv a0, s1 +; RV64I-NEXT: mv a1, s0 +; RV64I-NEXT: call __unordsf2 +; RV64I-NEXT: snez a0, a0 +; RV64I-NEXT: or a0, a0, s2 +; RV64I-NEXT: ld s2, 0(sp) +; RV64I-NEXT: ld s1, 8(sp) +; RV64I-NEXT: ld s0, 16(sp) +; RV64I-NEXT: ld ra, 24(sp) +; RV64I-NEXT: addi sp, sp, 32 +; RV64I-NEXT: ret %1 = fcmp ueq float %a, %b %2 = zext i1 %1 to i32 ret i32 %2 @@ -211,6 +331,17 @@ ; RV64IF-NEXT: fle.s a0, ft1, ft0 ; RV64IF-NEXT: xori a0, a0, 1 ; RV64IF-NEXT: ret +; +; RV64I-LABEL: fcmp_ugt: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: call __lesf2 +; RV64I-NEXT: sext.w a0, a0 +; RV64I-NEXT: sgtz a0, a0 +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret %1 = fcmp ugt float %a, %b %2 = zext i1 %1 to i32 ret i32 %2 @@ -232,6 +363,18 @@ ; RV64IF-NEXT: flt.s a0, ft1, ft0 ; RV64IF-NEXT: xori a0, a0, 1 ; RV64IF-NEXT: ret +; +; RV64I-LABEL: fcmp_uge: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: call __ltsf2 +; RV64I-NEXT: sext.w a0, a0 +; RV64I-NEXT: addi a1, zero, -1 +; RV64I-NEXT: slt a0, a1, a0 +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret %1 = fcmp uge float %a, %b %2 = zext i1 %1 to i32 ret i32 %2 @@ -253,6 +396,17 @@ ; RV64IF-NEXT: fle.s a0, ft1, ft0 ; RV64IF-NEXT: xori a0, a0, 1 ; RV64IF-NEXT: ret +; +; RV64I-LABEL: fcmp_ult: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: call __gesf2 +; RV64I-NEXT: sext.w a0, a0 +; RV64I-NEXT: slti a0, a0, 0 +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret %1 = fcmp ult float %a, %b %2 = zext i1 %1 to i32 ret i32 %2 @@ -274,6 +428,17 @@ ; RV64IF-NEXT: flt.s a0, ft1, ft0 ; RV64IF-NEXT: xori a0, a0, 1 ; RV64IF-NEXT: ret +; +; RV64I-LABEL: fcmp_ule: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: call __gtsf2 +; RV64I-NEXT: sext.w a0, a0 +; RV64I-NEXT: slti a0, a0, 1 +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret %1 = fcmp ule float %a, %b %2 = zext i1 %1 to i32 ret i32 %2 @@ -295,6 +460,16 @@ ; RV64IF-NEXT: feq.s a0, ft1, ft0 ; RV64IF-NEXT: xori a0, a0, 1 ; RV64IF-NEXT: ret +; +; RV64I-LABEL: fcmp_une: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: call __nesf2 +; RV64I-NEXT: snez a0, a0 +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret %1 = fcmp une float %a, %b %2 = zext i1 %1 to i32 ret i32 %2 @@ -320,6 +495,16 @@ ; RV64IF-NEXT: and a0, a0, a1 ; RV64IF-NEXT: seqz a0, a0 ; RV64IF-NEXT: ret +; +; RV64I-LABEL: fcmp_uno: +; RV64I: # %bb.0: +; RV64I-NEXT: addi sp, sp, -16 +; RV64I-NEXT: sd ra, 8(sp) +; RV64I-NEXT: call __unordsf2 +; RV64I-NEXT: snez a0, a0 +; RV64I-NEXT: ld ra, 8(sp) +; RV64I-NEXT: addi sp, sp, 16 +; RV64I-NEXT: ret %1 = fcmp uno float %a, %b %2 = zext i1 %1 to i32 ret i32 %2 @@ -335,6 +520,11 @@ ; RV64IF: # %bb.0: ; RV64IF-NEXT: addi a0, zero, 1 ; RV64IF-NEXT: ret +; +; RV64I-LABEL: fcmp_true: +; RV64I: # %bb.0: +; RV64I-NEXT: addi a0, zero, 1 +; RV64I-NEXT: ret %1 = fcmp true float %a, %b %2 = zext i1 %1 to i32 ret i32 %2 Index: test/CodeGen/RISCV/rv32i-rv64i-float-double.ll =================================================================== --- test/CodeGen/RISCV/rv32i-rv64i-float-double.ll +++ test/CodeGen/RISCV/rv32i-rv64i-float-double.ll @@ -31,11 +31,7 @@ ; RV64IF-NEXT: addi sp, sp, -16 ; RV64IF-NEXT: sd ra, 8(sp) ; RV64IF-NEXT: sd s0, 0(sp) -; RV64IF-NEXT: slli a0, a0, 32 -; RV64IF-NEXT: srli a0, a0, 32 -; RV64IF-NEXT: slli a1, a1, 32 -; RV64IF-NEXT: srli s0, a1, 32 -; RV64IF-NEXT: mv a1, s0 +; RV64IF-NEXT: mv s0, a1 ; RV64IF-NEXT: call __addsf3 ; RV64IF-NEXT: mv a1, s0 ; RV64IF-NEXT: call __divsf3 Index: test/CodeGen/RISCV/rv64-complex-float.ll =================================================================== --- /dev/null +++ test/CodeGen/RISCV/rv64-complex-float.ll @@ -0,0 +1,49 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s | FileCheck %s + +define i64 @complex_float_add(i64 %a.coerce, i64 %b.coerce) nounwind { +; CHECK-LABEL: complex_float_add: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: addi sp, sp, -32 +; CHECK-NEXT: sd ra, 24(sp) +; CHECK-NEXT: sd s0, 16(sp) +; CHECK-NEXT: sd s1, 8(sp) +; CHECK-NEXT: sd s2, 0(sp) +; CHECK-NEXT: mv s0, a1 +; CHECK-NEXT: mv s1, a0 +; CHECK-NEXT: call __addsf3 +; CHECK-NEXT: mv s2, a0 +; CHECK-NEXT: srli a0, s1, 32 +; CHECK-NEXT: srli a1, s0, 32 +; CHECK-NEXT: call __addsf3 +; CHECK-NEXT: slli a1, s2, 32 +; CHECK-NEXT: srli a1, a1, 32 +; CHECK-NEXT: slli a0, a0, 32 +; CHECK-NEXT: or a0, a0, a1 +; CHECK-NEXT: ld s2, 0(sp) +; CHECK-NEXT: ld s1, 8(sp) +; CHECK-NEXT: ld s0, 16(sp) +; CHECK-NEXT: ld ra, 24(sp) +; CHECK-NEXT: addi sp, sp, 32 +; CHECK-NEXT: ret +entry: + %a.sroa.0.0.extract.trunc = trunc i64 %a.coerce to i32 + %0 = bitcast i32 %a.sroa.0.0.extract.trunc to float + %a.sroa.2.0.extract.shift = lshr i64 %a.coerce, 32 + %a.sroa.2.0.extract.trunc = trunc i64 %a.sroa.2.0.extract.shift to i32 + %1 = bitcast i32 %a.sroa.2.0.extract.trunc to float + %b.sroa.0.0.extract.trunc = trunc i64 %b.coerce to i32 + %2 = bitcast i32 %b.sroa.0.0.extract.trunc to float + %b.sroa.2.0.extract.shift = lshr i64 %b.coerce, 32 + %b.sroa.2.0.extract.trunc = trunc i64 %b.sroa.2.0.extract.shift to i32 + %3 = bitcast i32 %b.sroa.2.0.extract.trunc to float + %add.r = fadd float %0, %2 + %add.i = fadd float %1, %3 + %4 = bitcast float %add.r to i32 + %5 = bitcast float %add.i to i32 + %retval.sroa.2.0.insert.ext = zext i32 %5 to i64 + %retval.sroa.2.0.insert.shift = shl nuw i64 %retval.sroa.2.0.insert.ext, 32 + %retval.sroa.0.0.insert.ext = zext i32 %4 to i64 + %retval.sroa.0.0.insert.insert = or i64 %retval.sroa.2.0.insert.shift, %retval.sroa.0.0.insert.ext + ret i64 %retval.sroa.0.0.insert.insert +}