; 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)
; 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
}
--- /dev/null
+; 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
+}