forked from OSchip/llvm-project
[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:
parent
37829b56a1
commit
52c27785ce
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
Loading…
Reference in New Issue