This doesn't bring us to parity with the test/CodeGen/RISCV/half-* test cases, it simply picks off an initial set that can be supported especially easy. In order to make the review more manageable, I'll follow up with other cases. There is zero innovation in the test cases - they simply take the existing half/float cases and replace f16->bf16 and half->bfloat. Differential Revision: https://reviews.llvm.org/D156895
500 lines
16 KiB
LLVM
500 lines
16 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2
|
|
; RUN: llc -mtriple=riscv32 -mattr=+experimental-zfbfmin -verify-machineinstrs \
|
|
; RUN: -target-abi ilp32f < %s | FileCheck -check-prefixes=CHECK,RV32IZFBFMIN %s
|
|
; RUN: llc -mtriple=riscv64 -mattr=+experimental-zfbfmin -verify-machineinstrs \
|
|
; RUN: -target-abi lp64f < %s | FileCheck -check-prefixes=CHECK,RV64IZFBFMIN %s
|
|
|
|
; These tests descend from float-arith.ll, where each function was targeted at
|
|
; a particular RISC-V FPU instruction.
|
|
|
|
define bfloat @fadd_s(bfloat %a, bfloat %b) nounwind {
|
|
; CHECK-LABEL: fadd_s:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: fcvt.s.bf16 fa5, fa1
|
|
; CHECK-NEXT: fcvt.s.bf16 fa4, fa0
|
|
; CHECK-NEXT: fadd.s fa5, fa4, fa5
|
|
; CHECK-NEXT: fcvt.bf16.s fa0, fa5
|
|
; CHECK-NEXT: ret
|
|
%1 = fadd bfloat %a, %b
|
|
ret bfloat %1
|
|
}
|
|
|
|
define bfloat @fsub_s(bfloat %a, bfloat %b) nounwind {
|
|
; CHECK-LABEL: fsub_s:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: fcvt.s.bf16 fa5, fa1
|
|
; CHECK-NEXT: fcvt.s.bf16 fa4, fa0
|
|
; CHECK-NEXT: fsub.s fa5, fa4, fa5
|
|
; CHECK-NEXT: fcvt.bf16.s fa0, fa5
|
|
; CHECK-NEXT: ret
|
|
%1 = fsub bfloat %a, %b
|
|
ret bfloat %1
|
|
}
|
|
|
|
define bfloat @fmul_s(bfloat %a, bfloat %b) nounwind {
|
|
; CHECK-LABEL: fmul_s:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: fcvt.s.bf16 fa5, fa1
|
|
; CHECK-NEXT: fcvt.s.bf16 fa4, fa0
|
|
; CHECK-NEXT: fmul.s fa5, fa4, fa5
|
|
; CHECK-NEXT: fcvt.bf16.s fa0, fa5
|
|
; CHECK-NEXT: ret
|
|
%1 = fmul bfloat %a, %b
|
|
ret bfloat %1
|
|
}
|
|
|
|
define bfloat @fdiv_s(bfloat %a, bfloat %b) nounwind {
|
|
; CHECK-LABEL: fdiv_s:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: fcvt.s.bf16 fa5, fa1
|
|
; CHECK-NEXT: fcvt.s.bf16 fa4, fa0
|
|
; CHECK-NEXT: fdiv.s fa5, fa4, fa5
|
|
; CHECK-NEXT: fcvt.bf16.s fa0, fa5
|
|
; CHECK-NEXT: ret
|
|
%1 = fdiv bfloat %a, %b
|
|
ret bfloat %1
|
|
}
|
|
|
|
declare bfloat @llvm.sqrt.bf16(bfloat)
|
|
|
|
define bfloat @fsqrt_s(bfloat %a) nounwind {
|
|
; CHECK-LABEL: fsqrt_s:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: fcvt.s.bf16 fa5, fa0
|
|
; CHECK-NEXT: fsqrt.s fa5, fa5
|
|
; CHECK-NEXT: fcvt.bf16.s fa0, fa5
|
|
; CHECK-NEXT: ret
|
|
%1 = call bfloat @llvm.sqrt.bf16(bfloat %a)
|
|
ret bfloat %1
|
|
}
|
|
|
|
declare bfloat @llvm.copysign.bf16(bfloat, bfloat)
|
|
|
|
define bfloat @fsgnj_s(bfloat %a, bfloat %b) nounwind {
|
|
; RV32IZFBFMIN-LABEL: fsgnj_s:
|
|
; RV32IZFBFMIN: # %bb.0:
|
|
; RV32IZFBFMIN-NEXT: addi sp, sp, -16
|
|
; RV32IZFBFMIN-NEXT: fsh fa1, 12(sp)
|
|
; RV32IZFBFMIN-NEXT: fsh fa0, 8(sp)
|
|
; RV32IZFBFMIN-NEXT: lbu a0, 13(sp)
|
|
; RV32IZFBFMIN-NEXT: lbu a1, 9(sp)
|
|
; RV32IZFBFMIN-NEXT: andi a0, a0, 128
|
|
; RV32IZFBFMIN-NEXT: andi a1, a1, 127
|
|
; RV32IZFBFMIN-NEXT: or a0, a1, a0
|
|
; RV32IZFBFMIN-NEXT: sb a0, 9(sp)
|
|
; RV32IZFBFMIN-NEXT: flh fa0, 8(sp)
|
|
; RV32IZFBFMIN-NEXT: addi sp, sp, 16
|
|
; RV32IZFBFMIN-NEXT: ret
|
|
;
|
|
; RV64IZFBFMIN-LABEL: fsgnj_s:
|
|
; RV64IZFBFMIN: # %bb.0:
|
|
; RV64IZFBFMIN-NEXT: addi sp, sp, -16
|
|
; RV64IZFBFMIN-NEXT: fsh fa1, 8(sp)
|
|
; RV64IZFBFMIN-NEXT: fsh fa0, 0(sp)
|
|
; RV64IZFBFMIN-NEXT: lbu a0, 9(sp)
|
|
; RV64IZFBFMIN-NEXT: lbu a1, 1(sp)
|
|
; RV64IZFBFMIN-NEXT: andi a0, a0, 128
|
|
; RV64IZFBFMIN-NEXT: andi a1, a1, 127
|
|
; RV64IZFBFMIN-NEXT: or a0, a1, a0
|
|
; RV64IZFBFMIN-NEXT: sb a0, 1(sp)
|
|
; RV64IZFBFMIN-NEXT: flh fa0, 0(sp)
|
|
; RV64IZFBFMIN-NEXT: addi sp, sp, 16
|
|
; RV64IZFBFMIN-NEXT: ret
|
|
%1 = call bfloat @llvm.copysign.bf16(bfloat %a, bfloat %b)
|
|
ret bfloat %1
|
|
}
|
|
|
|
define i32 @fneg_s(bfloat %a, bfloat %b) nounwind {
|
|
; CHECK-LABEL: fneg_s:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: fcvt.s.bf16 fa5, fa0
|
|
; CHECK-NEXT: fadd.s fa5, fa5, fa5
|
|
; CHECK-NEXT: fcvt.bf16.s fa5, fa5
|
|
; CHECK-NEXT: fcvt.s.bf16 fa5, fa5
|
|
; CHECK-NEXT: fneg.s fa4, fa5
|
|
; CHECK-NEXT: fcvt.bf16.s fa4, fa4
|
|
; CHECK-NEXT: fcvt.s.bf16 fa4, fa4
|
|
; CHECK-NEXT: feq.s a0, fa5, fa4
|
|
; CHECK-NEXT: ret
|
|
%1 = fadd bfloat %a, %a
|
|
%2 = fneg bfloat %1
|
|
%3 = fcmp oeq bfloat %1, %2
|
|
%4 = zext i1 %3 to i32
|
|
ret i32 %4
|
|
}
|
|
|
|
define bfloat @fsgnjn_s(bfloat %a, bfloat %b) nounwind {
|
|
; RV32IZFBFMIN-LABEL: fsgnjn_s:
|
|
; RV32IZFBFMIN: # %bb.0:
|
|
; RV32IZFBFMIN-NEXT: addi sp, sp, -16
|
|
; RV32IZFBFMIN-NEXT: fcvt.s.bf16 fa5, fa1
|
|
; RV32IZFBFMIN-NEXT: fcvt.s.bf16 fa4, fa0
|
|
; RV32IZFBFMIN-NEXT: fadd.s fa5, fa4, fa5
|
|
; RV32IZFBFMIN-NEXT: fcvt.bf16.s fa5, fa5
|
|
; RV32IZFBFMIN-NEXT: fcvt.s.bf16 fa5, fa5
|
|
; RV32IZFBFMIN-NEXT: fneg.s fa5, fa5
|
|
; RV32IZFBFMIN-NEXT: fcvt.bf16.s fa5, fa5
|
|
; RV32IZFBFMIN-NEXT: fsh fa0, 8(sp)
|
|
; RV32IZFBFMIN-NEXT: fsh fa5, 12(sp)
|
|
; RV32IZFBFMIN-NEXT: lbu a0, 9(sp)
|
|
; RV32IZFBFMIN-NEXT: lbu a1, 13(sp)
|
|
; RV32IZFBFMIN-NEXT: andi a0, a0, 127
|
|
; RV32IZFBFMIN-NEXT: andi a1, a1, 128
|
|
; RV32IZFBFMIN-NEXT: or a0, a0, a1
|
|
; RV32IZFBFMIN-NEXT: sb a0, 9(sp)
|
|
; RV32IZFBFMIN-NEXT: flh fa0, 8(sp)
|
|
; RV32IZFBFMIN-NEXT: addi sp, sp, 16
|
|
; RV32IZFBFMIN-NEXT: ret
|
|
;
|
|
; RV64IZFBFMIN-LABEL: fsgnjn_s:
|
|
; RV64IZFBFMIN: # %bb.0:
|
|
; RV64IZFBFMIN-NEXT: addi sp, sp, -16
|
|
; RV64IZFBFMIN-NEXT: fcvt.s.bf16 fa5, fa1
|
|
; RV64IZFBFMIN-NEXT: fcvt.s.bf16 fa4, fa0
|
|
; RV64IZFBFMIN-NEXT: fadd.s fa5, fa4, fa5
|
|
; RV64IZFBFMIN-NEXT: fcvt.bf16.s fa5, fa5
|
|
; RV64IZFBFMIN-NEXT: fcvt.s.bf16 fa5, fa5
|
|
; RV64IZFBFMIN-NEXT: fneg.s fa5, fa5
|
|
; RV64IZFBFMIN-NEXT: fcvt.bf16.s fa5, fa5
|
|
; RV64IZFBFMIN-NEXT: fsh fa0, 0(sp)
|
|
; RV64IZFBFMIN-NEXT: fsh fa5, 8(sp)
|
|
; RV64IZFBFMIN-NEXT: lbu a0, 1(sp)
|
|
; RV64IZFBFMIN-NEXT: lbu a1, 9(sp)
|
|
; RV64IZFBFMIN-NEXT: andi a0, a0, 127
|
|
; RV64IZFBFMIN-NEXT: andi a1, a1, 128
|
|
; RV64IZFBFMIN-NEXT: or a0, a0, a1
|
|
; RV64IZFBFMIN-NEXT: sb a0, 1(sp)
|
|
; RV64IZFBFMIN-NEXT: flh fa0, 0(sp)
|
|
; RV64IZFBFMIN-NEXT: addi sp, sp, 16
|
|
; RV64IZFBFMIN-NEXT: ret
|
|
%1 = fadd bfloat %a, %b
|
|
%2 = fneg bfloat %1
|
|
%3 = call bfloat @llvm.copysign.bf16(bfloat %a, bfloat %2)
|
|
ret bfloat %3
|
|
}
|
|
|
|
declare bfloat @llvm.fabs.bf16(bfloat)
|
|
|
|
define bfloat @fabs_s(bfloat %a, bfloat %b) nounwind {
|
|
; CHECK-LABEL: fabs_s:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: fcvt.s.bf16 fa5, fa1
|
|
; CHECK-NEXT: fcvt.s.bf16 fa4, fa0
|
|
; CHECK-NEXT: fadd.s fa5, fa4, fa5
|
|
; CHECK-NEXT: fcvt.bf16.s fa5, fa5
|
|
; CHECK-NEXT: fcvt.s.bf16 fa5, fa5
|
|
; CHECK-NEXT: fabs.s fa4, fa5
|
|
; CHECK-NEXT: fcvt.bf16.s fa4, fa4
|
|
; CHECK-NEXT: fcvt.s.bf16 fa4, fa4
|
|
; CHECK-NEXT: fadd.s fa5, fa4, fa5
|
|
; CHECK-NEXT: fcvt.bf16.s fa0, fa5
|
|
; CHECK-NEXT: ret
|
|
%1 = fadd bfloat %a, %b
|
|
%2 = call bfloat @llvm.fabs.bf16(bfloat %1)
|
|
%3 = fadd bfloat %2, %1
|
|
ret bfloat %3
|
|
}
|
|
|
|
declare bfloat @llvm.minnum.bf16(bfloat, bfloat)
|
|
|
|
define bfloat @fmin_s(bfloat %a, bfloat %b) nounwind {
|
|
; CHECK-LABEL: fmin_s:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: fcvt.s.bf16 fa5, fa1
|
|
; CHECK-NEXT: fcvt.s.bf16 fa4, fa0
|
|
; CHECK-NEXT: fmin.s fa5, fa4, fa5
|
|
; CHECK-NEXT: fcvt.bf16.s fa0, fa5
|
|
; CHECK-NEXT: ret
|
|
%1 = call bfloat @llvm.minnum.bf16(bfloat %a, bfloat %b)
|
|
ret bfloat %1
|
|
}
|
|
|
|
declare bfloat @llvm.maxnum.bf16(bfloat, bfloat)
|
|
|
|
define bfloat @fmax_s(bfloat %a, bfloat %b) nounwind {
|
|
; CHECK-LABEL: fmax_s:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: fcvt.s.bf16 fa5, fa1
|
|
; CHECK-NEXT: fcvt.s.bf16 fa4, fa0
|
|
; CHECK-NEXT: fmax.s fa5, fa4, fa5
|
|
; CHECK-NEXT: fcvt.bf16.s fa0, fa5
|
|
; CHECK-NEXT: ret
|
|
%1 = call bfloat @llvm.maxnum.bf16(bfloat %a, bfloat %b)
|
|
ret bfloat %1
|
|
}
|
|
|
|
declare bfloat @llvm.fma.bf16(bfloat, bfloat, bfloat)
|
|
|
|
define bfloat @fmadd_s(bfloat %a, bfloat %b, bfloat %c) nounwind {
|
|
; CHECK-LABEL: fmadd_s:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: fcvt.s.bf16 fa5, fa2
|
|
; CHECK-NEXT: fcvt.s.bf16 fa4, fa1
|
|
; CHECK-NEXT: fcvt.s.bf16 fa3, fa0
|
|
; CHECK-NEXT: fmadd.s fa5, fa3, fa4, fa5
|
|
; CHECK-NEXT: fcvt.bf16.s fa0, fa5
|
|
; CHECK-NEXT: ret
|
|
%1 = call bfloat @llvm.fma.bf16(bfloat %a, bfloat %b, bfloat %c)
|
|
ret bfloat %1
|
|
}
|
|
|
|
define bfloat @fmsub_s(bfloat %a, bfloat %b, bfloat %c) nounwind {
|
|
; CHECK-LABEL: fmsub_s:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: fcvt.s.bf16 fa5, fa2
|
|
; CHECK-NEXT: fmv.w.x fa4, zero
|
|
; CHECK-NEXT: fadd.s fa5, fa5, fa4
|
|
; CHECK-NEXT: fcvt.bf16.s fa5, fa5
|
|
; CHECK-NEXT: fcvt.s.bf16 fa5, fa5
|
|
; CHECK-NEXT: fneg.s fa5, fa5
|
|
; CHECK-NEXT: fcvt.bf16.s fa5, fa5
|
|
; CHECK-NEXT: fcvt.s.bf16 fa5, fa5
|
|
; CHECK-NEXT: fcvt.s.bf16 fa4, fa1
|
|
; CHECK-NEXT: fcvt.s.bf16 fa3, fa0
|
|
; CHECK-NEXT: fmadd.s fa5, fa3, fa4, fa5
|
|
; CHECK-NEXT: fcvt.bf16.s fa0, fa5
|
|
; CHECK-NEXT: ret
|
|
%c_ = fadd bfloat 0.0, %c ; avoid negation using xor
|
|
%negc = fsub bfloat -0.0, %c_
|
|
%1 = call bfloat @llvm.fma.bf16(bfloat %a, bfloat %b, bfloat %negc)
|
|
ret bfloat %1
|
|
}
|
|
|
|
define bfloat @fnmadd_s(bfloat %a, bfloat %b, bfloat %c) nounwind {
|
|
; CHECK-LABEL: fnmadd_s:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: fcvt.s.bf16 fa5, fa0
|
|
; CHECK-NEXT: fmv.w.x fa4, zero
|
|
; CHECK-NEXT: fadd.s fa5, fa5, fa4
|
|
; CHECK-NEXT: fcvt.bf16.s fa5, fa5
|
|
; CHECK-NEXT: fcvt.s.bf16 fa3, fa2
|
|
; CHECK-NEXT: fadd.s fa4, fa3, fa4
|
|
; CHECK-NEXT: fcvt.bf16.s fa4, fa4
|
|
; CHECK-NEXT: fcvt.s.bf16 fa5, fa5
|
|
; CHECK-NEXT: fneg.s fa5, fa5
|
|
; CHECK-NEXT: fcvt.bf16.s fa5, fa5
|
|
; CHECK-NEXT: fcvt.s.bf16 fa4, fa4
|
|
; CHECK-NEXT: fneg.s fa4, fa4
|
|
; CHECK-NEXT: fcvt.bf16.s fa4, fa4
|
|
; CHECK-NEXT: fcvt.s.bf16 fa4, fa4
|
|
; CHECK-NEXT: fcvt.s.bf16 fa5, fa5
|
|
; CHECK-NEXT: fcvt.s.bf16 fa3, fa1
|
|
; CHECK-NEXT: fmadd.s fa5, fa5, fa3, fa4
|
|
; CHECK-NEXT: fcvt.bf16.s fa0, fa5
|
|
; CHECK-NEXT: ret
|
|
%a_ = fadd bfloat 0.0, %a
|
|
%c_ = fadd bfloat 0.0, %c
|
|
%nega = fsub bfloat -0.0, %a_
|
|
%negc = fsub bfloat -0.0, %c_
|
|
%1 = call bfloat @llvm.fma.bf16(bfloat %nega, bfloat %b, bfloat %negc)
|
|
ret bfloat %1
|
|
}
|
|
|
|
define bfloat @fnmadd_s_2(bfloat %a, bfloat %b, bfloat %c) nounwind {
|
|
; CHECK-LABEL: fnmadd_s_2:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: fcvt.s.bf16 fa5, fa1
|
|
; CHECK-NEXT: fmv.w.x fa4, zero
|
|
; CHECK-NEXT: fadd.s fa5, fa5, fa4
|
|
; CHECK-NEXT: fcvt.bf16.s fa5, fa5
|
|
; CHECK-NEXT: fcvt.s.bf16 fa3, fa2
|
|
; CHECK-NEXT: fadd.s fa4, fa3, fa4
|
|
; CHECK-NEXT: fcvt.bf16.s fa4, fa4
|
|
; CHECK-NEXT: fcvt.s.bf16 fa5, fa5
|
|
; CHECK-NEXT: fneg.s fa5, fa5
|
|
; CHECK-NEXT: fcvt.bf16.s fa5, fa5
|
|
; CHECK-NEXT: fcvt.s.bf16 fa4, fa4
|
|
; CHECK-NEXT: fneg.s fa4, fa4
|
|
; CHECK-NEXT: fcvt.bf16.s fa4, fa4
|
|
; CHECK-NEXT: fcvt.s.bf16 fa4, fa4
|
|
; CHECK-NEXT: fcvt.s.bf16 fa5, fa5
|
|
; CHECK-NEXT: fcvt.s.bf16 fa3, fa0
|
|
; CHECK-NEXT: fmadd.s fa5, fa3, fa5, fa4
|
|
; CHECK-NEXT: fcvt.bf16.s fa0, fa5
|
|
; CHECK-NEXT: ret
|
|
%b_ = fadd bfloat 0.0, %b
|
|
%c_ = fadd bfloat 0.0, %c
|
|
%negb = fsub bfloat -0.0, %b_
|
|
%negc = fsub bfloat -0.0, %c_
|
|
%1 = call bfloat @llvm.fma.bf16(bfloat %a, bfloat %negb, bfloat %negc)
|
|
ret bfloat %1
|
|
}
|
|
|
|
define bfloat @fnmadd_s_3(bfloat %a, bfloat %b, bfloat %c) nounwind {
|
|
; CHECK-LABEL: fnmadd_s_3:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: fcvt.s.bf16 fa5, fa2
|
|
; CHECK-NEXT: fcvt.s.bf16 fa4, fa1
|
|
; CHECK-NEXT: fcvt.s.bf16 fa3, fa0
|
|
; CHECK-NEXT: fmadd.s fa5, fa3, fa4, fa5
|
|
; CHECK-NEXT: fcvt.bf16.s fa5, fa5
|
|
; CHECK-NEXT: fcvt.s.bf16 fa5, fa5
|
|
; CHECK-NEXT: fneg.s fa5, fa5
|
|
; CHECK-NEXT: fcvt.bf16.s fa0, fa5
|
|
; CHECK-NEXT: ret
|
|
%1 = call bfloat @llvm.fma.bf16(bfloat %a, bfloat %b, bfloat %c)
|
|
%neg = fneg bfloat %1
|
|
ret bfloat %neg
|
|
}
|
|
|
|
|
|
define bfloat @fnmadd_nsz(bfloat %a, bfloat %b, bfloat %c) nounwind {
|
|
; CHECK-LABEL: fnmadd_nsz:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: fcvt.s.bf16 fa5, fa2
|
|
; CHECK-NEXT: fcvt.s.bf16 fa4, fa1
|
|
; CHECK-NEXT: fcvt.s.bf16 fa3, fa0
|
|
; CHECK-NEXT: fmadd.s fa5, fa3, fa4, fa5
|
|
; CHECK-NEXT: fcvt.bf16.s fa5, fa5
|
|
; CHECK-NEXT: fcvt.s.bf16 fa5, fa5
|
|
; CHECK-NEXT: fneg.s fa5, fa5
|
|
; CHECK-NEXT: fcvt.bf16.s fa0, fa5
|
|
; CHECK-NEXT: ret
|
|
%1 = call nsz bfloat @llvm.fma.bf16(bfloat %a, bfloat %b, bfloat %c)
|
|
%neg = fneg nsz bfloat %1
|
|
ret bfloat %neg
|
|
}
|
|
|
|
define bfloat @fnmsub_s(bfloat %a, bfloat %b, bfloat %c) nounwind {
|
|
; CHECK-LABEL: fnmsub_s:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: fcvt.s.bf16 fa5, fa0
|
|
; CHECK-NEXT: fmv.w.x fa4, zero
|
|
; CHECK-NEXT: fadd.s fa5, fa5, fa4
|
|
; CHECK-NEXT: fcvt.bf16.s fa5, fa5
|
|
; CHECK-NEXT: fcvt.s.bf16 fa5, fa5
|
|
; CHECK-NEXT: fneg.s fa5, fa5
|
|
; CHECK-NEXT: fcvt.bf16.s fa5, fa5
|
|
; CHECK-NEXT: fcvt.s.bf16 fa5, fa5
|
|
; CHECK-NEXT: fcvt.s.bf16 fa4, fa2
|
|
; CHECK-NEXT: fcvt.s.bf16 fa3, fa1
|
|
; CHECK-NEXT: fmadd.s fa5, fa5, fa3, fa4
|
|
; CHECK-NEXT: fcvt.bf16.s fa0, fa5
|
|
; CHECK-NEXT: ret
|
|
%a_ = fadd bfloat 0.0, %a
|
|
%nega = fsub bfloat -0.0, %a_
|
|
%1 = call bfloat @llvm.fma.bf16(bfloat %nega, bfloat %b, bfloat %c)
|
|
ret bfloat %1
|
|
}
|
|
|
|
define bfloat @fnmsub_s_2(bfloat %a, bfloat %b, bfloat %c) nounwind {
|
|
; CHECK-LABEL: fnmsub_s_2:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: fcvt.s.bf16 fa5, fa1
|
|
; CHECK-NEXT: fmv.w.x fa4, zero
|
|
; CHECK-NEXT: fadd.s fa5, fa5, fa4
|
|
; CHECK-NEXT: fcvt.bf16.s fa5, fa5
|
|
; CHECK-NEXT: fcvt.s.bf16 fa5, fa5
|
|
; CHECK-NEXT: fneg.s fa5, fa5
|
|
; CHECK-NEXT: fcvt.bf16.s fa5, fa5
|
|
; CHECK-NEXT: fcvt.s.bf16 fa5, fa5
|
|
; CHECK-NEXT: fcvt.s.bf16 fa4, fa2
|
|
; CHECK-NEXT: fcvt.s.bf16 fa3, fa0
|
|
; CHECK-NEXT: fmadd.s fa5, fa3, fa5, fa4
|
|
; CHECK-NEXT: fcvt.bf16.s fa0, fa5
|
|
; CHECK-NEXT: ret
|
|
%b_ = fadd bfloat 0.0, %b
|
|
%negb = fsub bfloat -0.0, %b_
|
|
%1 = call bfloat @llvm.fma.bf16(bfloat %a, bfloat %negb, bfloat %c)
|
|
ret bfloat %1
|
|
}
|
|
|
|
define bfloat @fmadd_s_contract(bfloat %a, bfloat %b, bfloat %c) nounwind {
|
|
; CHECK-LABEL: fmadd_s_contract:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: fcvt.s.bf16 fa5, fa1
|
|
; CHECK-NEXT: fcvt.s.bf16 fa4, fa0
|
|
; CHECK-NEXT: fmul.s fa5, fa4, fa5
|
|
; CHECK-NEXT: fcvt.bf16.s fa5, fa5
|
|
; CHECK-NEXT: fcvt.s.bf16 fa5, fa5
|
|
; CHECK-NEXT: fcvt.s.bf16 fa4, fa2
|
|
; CHECK-NEXT: fadd.s fa5, fa5, fa4
|
|
; CHECK-NEXT: fcvt.bf16.s fa0, fa5
|
|
; CHECK-NEXT: ret
|
|
%1 = fmul contract bfloat %a, %b
|
|
%2 = fadd contract bfloat %1, %c
|
|
ret bfloat %2
|
|
}
|
|
|
|
define bfloat @fmsub_s_contract(bfloat %a, bfloat %b, bfloat %c) nounwind {
|
|
; CHECK-LABEL: fmsub_s_contract:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: fcvt.s.bf16 fa5, fa2
|
|
; CHECK-NEXT: fmv.w.x fa4, zero
|
|
; CHECK-NEXT: fadd.s fa5, fa5, fa4
|
|
; CHECK-NEXT: fcvt.bf16.s fa5, fa5
|
|
; CHECK-NEXT: fcvt.s.bf16 fa4, fa1
|
|
; CHECK-NEXT: fcvt.s.bf16 fa3, fa0
|
|
; CHECK-NEXT: fmul.s fa4, fa3, fa4
|
|
; CHECK-NEXT: fcvt.bf16.s fa4, fa4
|
|
; CHECK-NEXT: fcvt.s.bf16 fa5, fa5
|
|
; CHECK-NEXT: fcvt.s.bf16 fa4, fa4
|
|
; CHECK-NEXT: fsub.s fa5, fa4, fa5
|
|
; CHECK-NEXT: fcvt.bf16.s fa0, fa5
|
|
; CHECK-NEXT: ret
|
|
%c_ = fadd bfloat 0.0, %c ; avoid negation using xor
|
|
%1 = fmul contract bfloat %a, %b
|
|
%2 = fsub contract bfloat %1, %c_
|
|
ret bfloat %2
|
|
}
|
|
|
|
define bfloat @fnmadd_s_contract(bfloat %a, bfloat %b, bfloat %c) nounwind {
|
|
; CHECK-LABEL: fnmadd_s_contract:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: fcvt.s.bf16 fa5, fa0
|
|
; CHECK-NEXT: fmv.w.x fa4, zero
|
|
; CHECK-NEXT: fadd.s fa5, fa5, fa4
|
|
; CHECK-NEXT: fcvt.bf16.s fa5, fa5
|
|
; CHECK-NEXT: fcvt.s.bf16 fa3, fa1
|
|
; CHECK-NEXT: fadd.s fa3, fa3, fa4
|
|
; CHECK-NEXT: fcvt.bf16.s fa3, fa3
|
|
; CHECK-NEXT: fcvt.s.bf16 fa2, fa2
|
|
; CHECK-NEXT: fadd.s fa4, fa2, fa4
|
|
; CHECK-NEXT: fcvt.bf16.s fa4, fa4
|
|
; CHECK-NEXT: fcvt.s.bf16 fa3, fa3
|
|
; CHECK-NEXT: fcvt.s.bf16 fa5, fa5
|
|
; CHECK-NEXT: fmul.s fa5, fa5, fa3
|
|
; CHECK-NEXT: fcvt.bf16.s fa5, fa5
|
|
; CHECK-NEXT: fcvt.s.bf16 fa5, fa5
|
|
; CHECK-NEXT: fneg.s fa5, fa5
|
|
; CHECK-NEXT: fcvt.bf16.s fa5, fa5
|
|
; CHECK-NEXT: fcvt.s.bf16 fa5, fa5
|
|
; CHECK-NEXT: fcvt.s.bf16 fa4, fa4
|
|
; CHECK-NEXT: fsub.s fa5, fa5, fa4
|
|
; CHECK-NEXT: fcvt.bf16.s fa0, fa5
|
|
; CHECK-NEXT: ret
|
|
%a_ = fadd bfloat 0.0, %a ; avoid negation using xor
|
|
%b_ = fadd bfloat 0.0, %b ; avoid negation using xor
|
|
%c_ = fadd bfloat 0.0, %c ; avoid negation using xor
|
|
%1 = fmul contract bfloat %a_, %b_
|
|
%2 = fneg bfloat %1
|
|
%3 = fsub contract bfloat %2, %c_
|
|
ret bfloat %3
|
|
}
|
|
|
|
define bfloat @fnmsub_s_contract(bfloat %a, bfloat %b, bfloat %c) nounwind {
|
|
; CHECK-LABEL: fnmsub_s_contract:
|
|
; CHECK: # %bb.0:
|
|
; CHECK-NEXT: fcvt.s.bf16 fa5, fa0
|
|
; CHECK-NEXT: fmv.w.x fa4, zero
|
|
; CHECK-NEXT: fadd.s fa5, fa5, fa4
|
|
; CHECK-NEXT: fcvt.bf16.s fa5, fa5
|
|
; CHECK-NEXT: fcvt.s.bf16 fa3, fa1
|
|
; CHECK-NEXT: fadd.s fa4, fa3, fa4
|
|
; CHECK-NEXT: fcvt.bf16.s fa4, fa4
|
|
; CHECK-NEXT: fcvt.s.bf16 fa4, fa4
|
|
; CHECK-NEXT: fcvt.s.bf16 fa5, fa5
|
|
; CHECK-NEXT: fmul.s fa5, fa5, fa4
|
|
; CHECK-NEXT: fcvt.bf16.s fa5, fa5
|
|
; CHECK-NEXT: fcvt.s.bf16 fa5, fa5
|
|
; CHECK-NEXT: fcvt.s.bf16 fa4, fa2
|
|
; CHECK-NEXT: fsub.s fa5, fa4, fa5
|
|
; CHECK-NEXT: fcvt.bf16.s fa0, fa5
|
|
; CHECK-NEXT: ret
|
|
%a_ = fadd bfloat 0.0, %a ; avoid negation using xor
|
|
%b_ = fadd bfloat 0.0, %b ; avoid negation using xor
|
|
%1 = fmul contract bfloat %a_, %b_
|
|
%2 = fsub contract bfloat %c, %1
|
|
ret bfloat %2
|
|
}
|