Index: lib/Target/RISCV/RISCVISelLowering.cpp =================================================================== --- lib/Target/RISCV/RISCVISelLowering.cpp +++ lib/Target/RISCV/RISCVISelLowering.cpp @@ -111,6 +111,11 @@ ISD::SETUGT, ISD::SETUGE, ISD::SETULT, ISD::SETULE, ISD::SETUNE, ISD::SETGT, ISD::SETGE, ISD::SETNE}; + // TODO: add proper support for the various FMA variants + // (FMADD.S, FMSUB.S, FNMSUB.S, FNMADD.S). + ISD::NodeType FPOpToExtend[] = { + ISD::FSIN, ISD::FCOS, ISD::FSINCOS, ISD::FPOW, ISD::FMA}; + if (Subtarget.hasStdExtF()) { setOperationAction(ISD::FMINNUM, MVT::f32, Legal); setOperationAction(ISD::FMAXNUM, MVT::f32, Legal); @@ -119,6 +124,8 @@ setOperationAction(ISD::SELECT_CC, MVT::f32, Expand); setOperationAction(ISD::SELECT, MVT::f32, Custom); setOperationAction(ISD::BR_CC, MVT::f32, Expand); + for (auto Op : FPOpToExtend) + setOperationAction(Op, MVT::f32, Expand); } if (Subtarget.hasStdExtD()) { @@ -131,6 +138,8 @@ setOperationAction(ISD::BR_CC, MVT::f64, Expand); setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand); setTruncStoreAction(MVT::f64, MVT::f32, Expand); + for (auto Op : FPOpToExtend) + setOperationAction(Op, MVT::f64, Expand); } setOperationAction(ISD::GlobalAddress, XLenVT, Custom); Index: test/CodeGen/RISCV/double-intrinsics.ll =================================================================== --- test/CodeGen/RISCV/double-intrinsics.ll +++ test/CodeGen/RISCV/double-intrinsics.ll @@ -2,14 +2,323 @@ ; RUN: llc -mtriple=riscv32 -mattr=+d -verify-machineinstrs < %s \ ; RUN: | FileCheck -check-prefix=RV32IFD %s -declare double @llvm.floor.f64(double) +declare double @llvm.sqrt.f64(double) + +define double @sqrt_f64(double %a) { +; RV32IFD-LABEL: sqrt_f64: +; RV32IFD: # %bb.0: +; RV32IFD-NEXT: addi sp, sp, -16 +; RV32IFD-NEXT: sw a0, 8(sp) +; RV32IFD-NEXT: sw a1, 12(sp) +; RV32IFD-NEXT: fld ft0, 8(sp) +; RV32IFD-NEXT: fsqrt.d ft0, ft0 +; RV32IFD-NEXT: fsd ft0, 8(sp) +; RV32IFD-NEXT: lw a0, 8(sp) +; RV32IFD-NEXT: lw a1, 12(sp) +; RV32IFD-NEXT: addi sp, sp, 16 +; RV32IFD-NEXT: ret + %1 = call double @llvm.sqrt.f64(double %a) + ret double %1 +} + +declare double @llvm.powi.f64(double, i32) + +define double @powi_f64(double %a, i32 %b) { +; RV32IFD-LABEL: powi_f64: +; RV32IFD: # %bb.0: +; RV32IFD-NEXT: addi sp, sp, -16 +; RV32IFD-NEXT: sw ra, 12(sp) +; RV32IFD-NEXT: call __powidf2 +; RV32IFD-NEXT: lw ra, 12(sp) +; RV32IFD-NEXT: addi sp, sp, 16 +; RV32IFD-NEXT: ret + %1 = call double @llvm.powi.f64(double %a, i32 %b) + ret double %1 +} + +declare double @llvm.sin.f64(double) + +define double @sin_f64(double %a) { +; RV32IFD-LABEL: sin_f64: +; RV32IFD: # %bb.0: +; RV32IFD-NEXT: addi sp, sp, -16 +; RV32IFD-NEXT: sw ra, 12(sp) +; RV32IFD-NEXT: call sin +; RV32IFD-NEXT: lw ra, 12(sp) +; RV32IFD-NEXT: addi sp, sp, 16 +; RV32IFD-NEXT: ret + %1 = call double @llvm.sin.f64(double %a) + ret double %1 +} + +declare double @llvm.cos.f64(double) + +define double @cos_f64(double %a) { +; RV32IFD-LABEL: cos_f64: +; RV32IFD: # %bb.0: +; RV32IFD-NEXT: addi sp, sp, -16 +; RV32IFD-NEXT: sw ra, 12(sp) +; RV32IFD-NEXT: call cos +; RV32IFD-NEXT: lw ra, 12(sp) +; RV32IFD-NEXT: addi sp, sp, 16 +; RV32IFD-NEXT: ret + %1 = call double @llvm.cos.f64(double %a) + ret double %1 +} + +; The sin+cos combination results in an FSINCOS SelectionDAG node. +define double @sincos_f64(double %a) { +; RV32IFD-LABEL: sincos_f64: +; RV32IFD: # %bb.0: +; RV32IFD-NEXT: addi sp, sp, -32 +; RV32IFD-NEXT: sw ra, 28(sp) +; RV32IFD-NEXT: sw s1, 24(sp) +; RV32IFD-NEXT: sw s2, 20(sp) +; RV32IFD-NEXT: sw s3, 16(sp) +; RV32IFD-NEXT: sw s4, 12(sp) +; RV32IFD-NEXT: mv s2, a1 +; RV32IFD-NEXT: mv s1, a0 +; RV32IFD-NEXT: call sin +; RV32IFD-NEXT: mv s3, a0 +; RV32IFD-NEXT: mv s4, a1 +; RV32IFD-NEXT: mv a0, s1 +; RV32IFD-NEXT: mv a1, s2 +; RV32IFD-NEXT: call cos +; RV32IFD-NEXT: sw a0, 0(sp) +; RV32IFD-NEXT: sw a1, 4(sp) +; RV32IFD-NEXT: fld ft0, 0(sp) +; RV32IFD-NEXT: sw s3, 0(sp) +; RV32IFD-NEXT: sw s4, 4(sp) +; RV32IFD-NEXT: fld ft1, 0(sp) +; RV32IFD-NEXT: fadd.d ft0, ft1, ft0 +; RV32IFD-NEXT: fsd ft0, 0(sp) +; RV32IFD-NEXT: lw a0, 0(sp) +; RV32IFD-NEXT: lw a1, 4(sp) +; RV32IFD-NEXT: lw s4, 12(sp) +; RV32IFD-NEXT: lw s3, 16(sp) +; RV32IFD-NEXT: lw s2, 20(sp) +; RV32IFD-NEXT: lw s1, 24(sp) +; RV32IFD-NEXT: lw ra, 28(sp) +; RV32IFD-NEXT: addi sp, sp, 32 +; RV32IFD-NEXT: ret + %1 = call double @llvm.sin.f64(double %a) + %2 = call double @llvm.cos.f64(double %a) + %3 = fadd double %1, %2 + ret double %3 +} + +declare double @llvm.pow.f64(double, double) + +define double @pow_f64(double %a, double %b) { +; RV32IFD-LABEL: pow_f64: +; RV32IFD: # %bb.0: +; RV32IFD-NEXT: addi sp, sp, -16 +; RV32IFD-NEXT: sw ra, 12(sp) +; RV32IFD-NEXT: call pow +; RV32IFD-NEXT: lw ra, 12(sp) +; RV32IFD-NEXT: addi sp, sp, 16 +; RV32IFD-NEXT: ret + %1 = call double @llvm.pow.f64(double %a, double %b) + ret double %1 +} + +declare double @llvm.exp.f64(double) + +define double @exp_f64(double %a) { +; RV32IFD-LABEL: exp_f64: +; RV32IFD: # %bb.0: +; RV32IFD-NEXT: addi sp, sp, -16 +; RV32IFD-NEXT: sw ra, 12(sp) +; RV32IFD-NEXT: call exp +; RV32IFD-NEXT: lw ra, 12(sp) +; RV32IFD-NEXT: addi sp, sp, 16 +; RV32IFD-NEXT: ret + %1 = call double @llvm.exp.f64(double %a) + ret double %1 +} + +declare double @llvm.exp2.f64(double) + +define double @exp2_f64(double %a) { +; RV32IFD-LABEL: exp2_f64: +; RV32IFD: # %bb.0: +; RV32IFD-NEXT: addi sp, sp, -16 +; RV32IFD-NEXT: sw ra, 12(sp) +; RV32IFD-NEXT: call exp2 +; RV32IFD-NEXT: lw ra, 12(sp) +; RV32IFD-NEXT: addi sp, sp, 16 +; RV32IFD-NEXT: ret + %1 = call double @llvm.exp2.f64(double %a) + ret double %1 +} + +declare double @llvm.log.f64(double) + +define double @log_f64(double %a) { +; RV32IFD-LABEL: log_f64: +; RV32IFD: # %bb.0: +; RV32IFD-NEXT: addi sp, sp, -16 +; RV32IFD-NEXT: sw ra, 12(sp) +; RV32IFD-NEXT: call log +; RV32IFD-NEXT: lw ra, 12(sp) +; RV32IFD-NEXT: addi sp, sp, 16 +; RV32IFD-NEXT: ret + %1 = call double @llvm.log.f64(double %a) + ret double %1 +} + +declare double @llvm.log10.f64(double) + +define double @log10_f64(double %a) { +; RV32IFD-LABEL: log10_f64: +; RV32IFD: # %bb.0: +; RV32IFD-NEXT: addi sp, sp, -16 +; RV32IFD-NEXT: sw ra, 12(sp) +; RV32IFD-NEXT: call log10 +; RV32IFD-NEXT: lw ra, 12(sp) +; RV32IFD-NEXT: addi sp, sp, 16 +; RV32IFD-NEXT: ret + %1 = call double @llvm.log10.f64(double %a) + ret double %1 +} + +declare double @llvm.log2.f64(double) + +define double @log2_f64(double %a) { +; RV32IFD-LABEL: log2_f64: +; RV32IFD: # %bb.0: +; RV32IFD-NEXT: addi sp, sp, -16 +; RV32IFD-NEXT: sw ra, 12(sp) +; RV32IFD-NEXT: call log2 +; RV32IFD-NEXT: lw ra, 12(sp) +; RV32IFD-NEXT: addi sp, sp, 16 +; RV32IFD-NEXT: ret + %1 = call double @llvm.log2.f64(double %a) + ret double %1 +} -; The call to ffloor is introduced very late, meaning this test case covers -; aspects of passing f64 on RV32D soft-float that double-calling-conv.ll -; doesn't. +declare double @llvm.fma.f64(double, double, double) -define double @foo(double %a) nounwind { -; RV32IFD-LABEL: foo: +; TODO: Select RISC-V FMA instruction. +define double @fma_f64(double %a, double %b, double %c) { +; RV32IFD-LABEL: fma_f64: +; RV32IFD: # %bb.0: +; RV32IFD-NEXT: addi sp, sp, -16 +; RV32IFD-NEXT: sw ra, 12(sp) +; RV32IFD-NEXT: call fma +; RV32IFD-NEXT: lw ra, 12(sp) +; RV32IFD-NEXT: addi sp, sp, 16 +; RV32IFD-NEXT: ret + %1 = call double @llvm.fma.f64(double %a, double %b, double %c) + ret double %1 +} + +declare double @llvm.fabs.f64(double) + +define double @fabs_f64(double %a) { +; RV32IFD-LABEL: fabs_f64: +; RV32IFD: # %bb.0: +; RV32IFD-NEXT: addi sp, sp, -16 +; RV32IFD-NEXT: sw a0, 8(sp) +; RV32IFD-NEXT: sw a1, 12(sp) +; RV32IFD-NEXT: fld ft0, 8(sp) +; RV32IFD-NEXT: fabs.d ft0, ft0 +; RV32IFD-NEXT: fsd ft0, 8(sp) +; RV32IFD-NEXT: lw a0, 8(sp) +; RV32IFD-NEXT: lw a1, 12(sp) +; RV32IFD-NEXT: addi sp, sp, 16 +; RV32IFD-NEXT: ret + %1 = call double @llvm.fabs.f64(double %a) + ret double %1 +} + +declare double @llvm.minnum.f64(double, double) + +define double @minnum_f64(double %a, double %b) nounwind { +; RV32IFD-LABEL: minnum_f64: +; RV32IFD: # %bb.0: +; RV32IFD-NEXT: addi sp, sp, -16 +; RV32IFD-NEXT: sw a2, 8(sp) +; RV32IFD-NEXT: sw a3, 12(sp) +; RV32IFD-NEXT: fld ft0, 8(sp) +; RV32IFD-NEXT: sw a0, 8(sp) +; RV32IFD-NEXT: sw a1, 12(sp) +; RV32IFD-NEXT: fld ft1, 8(sp) +; RV32IFD-NEXT: fmin.d ft0, ft1, ft0 +; RV32IFD-NEXT: fsd ft0, 8(sp) +; RV32IFD-NEXT: lw a0, 8(sp) +; RV32IFD-NEXT: lw a1, 12(sp) +; RV32IFD-NEXT: addi sp, sp, 16 +; RV32IFD-NEXT: ret + %1 = call double @llvm.minnum.f64(double %a, double %b) + ret double %1 +} + +declare double @llvm.maxnum.f64(double, double) + +define double @maxnum_f64(double %a, double %b) nounwind { +; RV32IFD-LABEL: maxnum_f64: +; RV32IFD: # %bb.0: +; RV32IFD-NEXT: addi sp, sp, -16 +; RV32IFD-NEXT: sw a2, 8(sp) +; RV32IFD-NEXT: sw a3, 12(sp) +; RV32IFD-NEXT: fld ft0, 8(sp) +; RV32IFD-NEXT: sw a0, 8(sp) +; RV32IFD-NEXT: sw a1, 12(sp) +; RV32IFD-NEXT: fld ft1, 8(sp) +; RV32IFD-NEXT: fmax.d ft0, ft1, ft0 +; RV32IFD-NEXT: fsd ft0, 8(sp) +; RV32IFD-NEXT: lw a0, 8(sp) +; RV32IFD-NEXT: lw a1, 12(sp) +; RV32IFD-NEXT: addi sp, sp, 16 +; RV32IFD-NEXT: ret + %1 = call double @llvm.maxnum.f64(double %a, double %b) + ret double %1 +} + +; TODO: FMINNAN and FMAXNAN aren't handled in +; SelectionDAGLegalize::ExpandNode. + +; declare double @llvm.minimum.f64(double, double) + +; define double @fminimum_f64(double %a, double %b) nounwind { +; %1 = call double @llvm.minimum.f64(double %a, double %b) +; ret double %1 +; } + +; declare double @llvm.maximum.f64(double, double) + +; define double @fmaximum_f64(double %a, double %b) nounwind { +; %1 = call double @llvm.maximum.f64(double %a, double %b) +; ret double %1 +; } + +declare double @llvm.copysign.f64(double, double) + +define double @copysign_f64(double %a, double %b) nounwind { +; RV32IFD-LABEL: copysign_f64: +; RV32IFD: # %bb.0: +; RV32IFD-NEXT: addi sp, sp, -16 +; RV32IFD-NEXT: sw a2, 8(sp) +; RV32IFD-NEXT: sw a3, 12(sp) +; RV32IFD-NEXT: fld ft0, 8(sp) +; RV32IFD-NEXT: sw a0, 8(sp) +; RV32IFD-NEXT: sw a1, 12(sp) +; RV32IFD-NEXT: fld ft1, 8(sp) +; RV32IFD-NEXT: fsgnj.d ft0, ft1, ft0 +; RV32IFD-NEXT: fsd ft0, 8(sp) +; RV32IFD-NEXT: lw a0, 8(sp) +; RV32IFD-NEXT: lw a1, 12(sp) +; RV32IFD-NEXT: addi sp, sp, 16 +; RV32IFD-NEXT: ret + %1 = call double @llvm.copysign.f64(double %a, double %b) + ret double %1 +} + +declare double @llvm.floor.f64(double) + +define double @floor_f64(double %a) { +; RV32IFD-LABEL: floor_f64: ; RV32IFD: # %bb.0: ; RV32IFD-NEXT: addi sp, sp, -16 ; RV32IFD-NEXT: sw ra, 12(sp) @@ -18,5 +327,80 @@ ; RV32IFD-NEXT: addi sp, sp, 16 ; RV32IFD-NEXT: ret %1 = call double @llvm.floor.f64(double %a) - ret double %1 + ret double %1 +} + +declare double @llvm.ceil.f64(double) + +define double @ceil_f64(double %a) { +; RV32IFD-LABEL: ceil_f64: +; RV32IFD: # %bb.0: +; RV32IFD-NEXT: addi sp, sp, -16 +; RV32IFD-NEXT: sw ra, 12(sp) +; RV32IFD-NEXT: call ceil +; RV32IFD-NEXT: lw ra, 12(sp) +; RV32IFD-NEXT: addi sp, sp, 16 +; RV32IFD-NEXT: ret + %1 = call double @llvm.ceil.f64(double %a) + ret double %1 +} + +declare double @llvm.trunc.f64(double) + +define double @trunc_f64(double %a) { +; RV32IFD-LABEL: trunc_f64: +; RV32IFD: # %bb.0: +; RV32IFD-NEXT: addi sp, sp, -16 +; RV32IFD-NEXT: sw ra, 12(sp) +; RV32IFD-NEXT: call trunc +; RV32IFD-NEXT: lw ra, 12(sp) +; RV32IFD-NEXT: addi sp, sp, 16 +; RV32IFD-NEXT: ret + %1 = call double @llvm.trunc.f64(double %a) + ret double %1 +} + +declare double @llvm.rint.f64(double) + +define double @rint_f64(double %a) { +; RV32IFD-LABEL: rint_f64: +; RV32IFD: # %bb.0: +; RV32IFD-NEXT: addi sp, sp, -16 +; RV32IFD-NEXT: sw ra, 12(sp) +; RV32IFD-NEXT: call rint +; RV32IFD-NEXT: lw ra, 12(sp) +; RV32IFD-NEXT: addi sp, sp, 16 +; RV32IFD-NEXT: ret + %1 = call double @llvm.rint.f64(double %a) + ret double %1 +} + +declare double @llvm.nearbyint.f64(double) + +define double @nearbyint_f64(double %a) { +; RV32IFD-LABEL: nearbyint_f64: +; RV32IFD: # %bb.0: +; RV32IFD-NEXT: addi sp, sp, -16 +; RV32IFD-NEXT: sw ra, 12(sp) +; RV32IFD-NEXT: call nearbyint +; RV32IFD-NEXT: lw ra, 12(sp) +; RV32IFD-NEXT: addi sp, sp, 16 +; RV32IFD-NEXT: ret + %1 = call double @llvm.nearbyint.f64(double %a) + ret double %1 +} + +declare double @llvm.round.f64(double) + +define double @round_f64(double %a) { +; RV32IFD-LABEL: round_f64: +; RV32IFD: # %bb.0: +; RV32IFD-NEXT: addi sp, sp, -16 +; RV32IFD-NEXT: sw ra, 12(sp) +; RV32IFD-NEXT: call round +; RV32IFD-NEXT: lw ra, 12(sp) +; RV32IFD-NEXT: addi sp, sp, 16 +; RV32IFD-NEXT: ret + %1 = call double @llvm.round.f64(double %a) + ret double %1 } Index: test/CodeGen/RISCV/float-intrinsics.ll =================================================================== --- /dev/null +++ test/CodeGen/RISCV/float-intrinsics.ll @@ -0,0 +1,359 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 -mattr=+f -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=RV32IF %s +; RUN: llc -mtriple=riscv32 -mattr=+d -verify-machineinstrs < %s \ +; RUN: | FileCheck -check-prefix=RV32IF %s + +declare float @llvm.sqrt.f32(float) + +define float @sqrt_f32(float %a) { +; RV32IF-LABEL: sqrt_f32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fmv.w.x ft0, a0 +; RV32IF-NEXT: fsqrt.s ft0, ft0 +; RV32IF-NEXT: fmv.x.w a0, ft0 +; RV32IF-NEXT: ret + %1 = call float @llvm.sqrt.f32(float %a) + ret float %1 +} + +declare float @llvm.powi.f32(float, i32) + +define float @powi_f32(float %a, i32 %b) { +; RV32IF-LABEL: powi_f32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: sw ra, 12(sp) +; RV32IF-NEXT: call __powisf2 +; RV32IF-NEXT: lw ra, 12(sp) +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret + %1 = call float @llvm.powi.f32(float %a, i32 %b) + ret float %1 +} + +declare float @llvm.sin.f32(float) + +define float @sin_f32(float %a) { +; RV32IF-LABEL: sin_f32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: sw ra, 12(sp) +; RV32IF-NEXT: call sinf +; RV32IF-NEXT: lw ra, 12(sp) +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret + %1 = call float @llvm.sin.f32(float %a) + ret float %1 +} + +declare float @llvm.cos.f32(float) + +define float @cos_f32(float %a) { +; RV32IF-LABEL: cos_f32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: sw ra, 12(sp) +; RV32IF-NEXT: call cosf +; RV32IF-NEXT: lw ra, 12(sp) +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret + %1 = call float @llvm.cos.f32(float %a) + ret float %1 +} + +; The sin+cos combination results in an FSINCOS SelectionDAG node. +define float @sincos_f32(float %a) { +; RV32IF-LABEL: sincos_f32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: sw ra, 12(sp) +; RV32IF-NEXT: sw s1, 8(sp) +; RV32IF-NEXT: sw s2, 4(sp) +; RV32IF-NEXT: mv s1, a0 +; RV32IF-NEXT: call sinf +; RV32IF-NEXT: mv s2, a0 +; RV32IF-NEXT: mv a0, s1 +; RV32IF-NEXT: call cosf +; RV32IF-NEXT: fmv.w.x ft0, a0 +; RV32IF-NEXT: fmv.w.x ft1, s2 +; RV32IF-NEXT: fadd.s ft0, ft1, ft0 +; RV32IF-NEXT: fmv.x.w a0, ft0 +; RV32IF-NEXT: lw s2, 4(sp) +; RV32IF-NEXT: lw s1, 8(sp) +; RV32IF-NEXT: lw ra, 12(sp) +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret + %1 = call float @llvm.sin.f32(float %a) + %2 = call float @llvm.cos.f32(float %a) + %3 = fadd float %1, %2 + ret float %3 +} + +declare float @llvm.pow.f32(float, float) + +define float @pow_f32(float %a, float %b) { +; RV32IF-LABEL: pow_f32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: sw ra, 12(sp) +; RV32IF-NEXT: call powf +; RV32IF-NEXT: lw ra, 12(sp) +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret + %1 = call float @llvm.pow.f32(float %a, float %b) + ret float %1 +} + +declare float @llvm.exp.f32(float) + +define float @exp_f32(float %a) { +; RV32IF-LABEL: exp_f32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: sw ra, 12(sp) +; RV32IF-NEXT: call expf +; RV32IF-NEXT: lw ra, 12(sp) +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret + %1 = call float @llvm.exp.f32(float %a) + ret float %1 +} + +declare float @llvm.exp2.f32(float) + +define float @exp2_f32(float %a) { +; RV32IF-LABEL: exp2_f32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: sw ra, 12(sp) +; RV32IF-NEXT: call exp2f +; RV32IF-NEXT: lw ra, 12(sp) +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret + %1 = call float @llvm.exp2.f32(float %a) + ret float %1 +} + +declare float @llvm.log.f32(float) + +define float @log_f32(float %a) { +; RV32IF-LABEL: log_f32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: sw ra, 12(sp) +; RV32IF-NEXT: call logf +; RV32IF-NEXT: lw ra, 12(sp) +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret + %1 = call float @llvm.log.f32(float %a) + ret float %1 +} + +declare float @llvm.log10.f32(float) + +define float @log10_f32(float %a) { +; RV32IF-LABEL: log10_f32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: sw ra, 12(sp) +; RV32IF-NEXT: call log10f +; RV32IF-NEXT: lw ra, 12(sp) +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret + %1 = call float @llvm.log10.f32(float %a) + ret float %1 +} + +declare float @llvm.log2.f32(float) + +define float @log2_f32(float %a) { +; RV32IF-LABEL: log2_f32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: sw ra, 12(sp) +; RV32IF-NEXT: call log2f +; RV32IF-NEXT: lw ra, 12(sp) +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret + %1 = call float @llvm.log2.f32(float %a) + ret float %1 +} + +declare float @llvm.fma.f32(float, float, float) + +; TODO: Select RISC-V FMA instruction. +define float @fma_f32(float %a, float %b, float %c) { +; RV32IF-LABEL: fma_f32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: sw ra, 12(sp) +; RV32IF-NEXT: call fmaf +; RV32IF-NEXT: lw ra, 12(sp) +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret + %1 = call float @llvm.fma.f32(float %a, float %b, float %c) + ret float %1 +} + +declare float @llvm.fabs.f32(float) + +define float @fabs_f32(float %a) { +; RV32IF-LABEL: fabs_f32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: lui a1, 524288 +; RV32IF-NEXT: addi a1, a1, -1 +; RV32IF-NEXT: and a0, a0, a1 +; RV32IF-NEXT: ret + %1 = call float @llvm.fabs.f32(float %a) + ret float %1 +} + +declare float @llvm.minnum.f32(float, float) + +define float @minnum_f32(float %a, float %b) nounwind { +; RV32IF-LABEL: minnum_f32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fmv.w.x ft0, a1 +; RV32IF-NEXT: fmv.w.x ft1, a0 +; RV32IF-NEXT: fmin.s ft0, ft1, ft0 +; RV32IF-NEXT: fmv.x.w a0, ft0 +; RV32IF-NEXT: ret + %1 = call float @llvm.minnum.f32(float %a, float %b) + ret float %1 +} + +declare float @llvm.maxnum.f32(float, float) + +define float @maxnum_f32(float %a, float %b) nounwind { +; RV32IF-LABEL: maxnum_f32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fmv.w.x ft0, a1 +; RV32IF-NEXT: fmv.w.x ft1, a0 +; RV32IF-NEXT: fmax.s ft0, ft1, ft0 +; RV32IF-NEXT: fmv.x.w a0, ft0 +; RV32IF-NEXT: ret + %1 = call float @llvm.maxnum.f32(float %a, float %b) + ret float %1 +} + +; TODO: FMINNAN and FMAXNAN aren't handled in +; SelectionDAGLegalize::ExpandNode. + +; declare float @llvm.minimum.f32(float, float) + +; define float @fminimum_f32(float %a, float %b) nounwind { +; %1 = call float @llvm.minimum.f32(float %a, float %b) +; ret float %1 +; } + +; declare float @llvm.maximum.f32(float, float) + +; define float @fmaximum_f32(float %a, float %b) nounwind { +; %1 = call float @llvm.maximum.f32(float %a, float %b) +; ret float %1 +; } + +declare float @llvm.copysign.f32(float, float) + +define float @copysign_f32(float %a, float %b) nounwind { +; RV32IF-LABEL: copysign_f32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: fmv.w.x ft0, a1 +; RV32IF-NEXT: fmv.w.x ft1, a0 +; RV32IF-NEXT: fsgnj.s ft0, ft1, ft0 +; RV32IF-NEXT: fmv.x.w a0, ft0 +; RV32IF-NEXT: ret + %1 = call float @llvm.copysign.f32(float %a, float %b) + ret float %1 +} + +declare float @llvm.floor.f32(float) + +define float @floor_f32(float %a) { +; RV32IF-LABEL: floor_f32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: sw ra, 12(sp) +; RV32IF-NEXT: call floorf +; RV32IF-NEXT: lw ra, 12(sp) +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret + %1 = call float @llvm.floor.f32(float %a) + ret float %1 +} + +declare float @llvm.ceil.f32(float) + +define float @ceil_f32(float %a) { +; RV32IF-LABEL: ceil_f32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: sw ra, 12(sp) +; RV32IF-NEXT: call ceilf +; RV32IF-NEXT: lw ra, 12(sp) +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret + %1 = call float @llvm.ceil.f32(float %a) + ret float %1 +} + +declare float @llvm.trunc.f32(float) + +define float @trunc_f32(float %a) { +; RV32IF-LABEL: trunc_f32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: sw ra, 12(sp) +; RV32IF-NEXT: call truncf +; RV32IF-NEXT: lw ra, 12(sp) +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret + %1 = call float @llvm.trunc.f32(float %a) + ret float %1 +} + +declare float @llvm.rint.f32(float) + +define float @rint_f32(float %a) { +; RV32IF-LABEL: rint_f32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: sw ra, 12(sp) +; RV32IF-NEXT: call rintf +; RV32IF-NEXT: lw ra, 12(sp) +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret + %1 = call float @llvm.rint.f32(float %a) + ret float %1 +} + +declare float @llvm.nearbyint.f32(float) + +define float @nearbyint_f32(float %a) { +; RV32IF-LABEL: nearbyint_f32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: sw ra, 12(sp) +; RV32IF-NEXT: call nearbyintf +; RV32IF-NEXT: lw ra, 12(sp) +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret + %1 = call float @llvm.nearbyint.f32(float %a) + ret float %1 +} + +declare float @llvm.round.f32(float) + +define float @round_f32(float %a) { +; RV32IF-LABEL: round_f32: +; RV32IF: # %bb.0: +; RV32IF-NEXT: addi sp, sp, -16 +; RV32IF-NEXT: sw ra, 12(sp) +; RV32IF-NEXT: call roundf +; RV32IF-NEXT: lw ra, 12(sp) +; RV32IF-NEXT: addi sp, sp, 16 +; RV32IF-NEXT: ret + %1 = call float @llvm.round.f32(float %a) + ret float %1 +}