[RISCV] Add some missing expansions for floating-point intrinsics

A number of intrinsics, such as llvm.sin.f32, would result in a failure to 
select. This patch adds expansions for the relevant selection DAG nodes, as 
well as exhaustive testing for all f32 and f64 intrinsics.

The codegen for FMA remains a TODO item, pending support for the various 
RISC-V FMA instruction variants.

The llvm.minimum.f32.* and llvm.maximum.* tests are commented-out, pending 
upstream support for target-independent expansion, as discussed in 
http://lists.llvm.org/pipermail/llvm-dev/2018-November/127408.html.

Differential Revision: https://reviews.llvm.org/D54034
Patch by Luís Marques.

llvm-svn: 346034
This commit is contained in:
Alex Bradbury 2018-11-02 19:50:38 +00:00
parent 37829b56a1
commit 52c27785ce
3 changed files with 759 additions and 7 deletions

View File

@ -111,6 +111,11 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
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 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
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 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
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);

View File

@ -2,14 +2,323 @@
; RUN: llc -mtriple=riscv32 -mattr=+d -verify-machineinstrs < %s \
; RUN: | FileCheck -check-prefix=RV32IFD %s
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
}
declare double @llvm.fma.f64(double, double, double)
; 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)
; 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.
define double @foo(double %a) nounwind {
; RV32IFD-LABEL: foo:
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 @@ define double @foo(double %a) nounwind {
; 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
}

View File

@ -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
}