llvm/llvm/test/CodeGen/RISCV/bfloat-arith.ll

; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2
; RUN: llc -mtriple=riscv32 -mattr=+zfbfmin -verify-machineinstrs \
; RUN:   -target-abi ilp32f < %s | FileCheck -check-prefixes=CHECK,RV32IZFBFMIN %s
; RUN: llc -mtriple=riscv64 -mattr=+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_bf16(bfloat %a, bfloat %b) nounwind {
; CHECK-LABEL: fadd_bf16:
; 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_bf16(bfloat %a, bfloat %b) nounwind {
; CHECK-LABEL: fsub_bf16:
; 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_bf16(bfloat %a, bfloat %b) nounwind {
; CHECK-LABEL: fmul_bf16:
; 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_bf16(bfloat %a, bfloat %b) nounwind {
; CHECK-LABEL: fdiv_bf16:
; 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_bf16(bfloat %a) nounwind {
; CHECK-LABEL: fsqrt_bf16:
; 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_bf16(bfloat %a, bfloat %b) nounwind {
; RV32IZFBFMIN-LABEL: fsgnj_bf16:
; RV32IZFBFMIN:       # %bb.0:
; RV32IZFBFMIN-NEXT:    fmv.x.h a0, fa1
; RV32IZFBFMIN-NEXT:    lui a1, 1048568
; RV32IZFBFMIN-NEXT:    and a0, a0, a1
; RV32IZFBFMIN-NEXT:    fmv.x.h a1, fa0
; RV32IZFBFMIN-NEXT:    slli a1, a1, 17
; RV32IZFBFMIN-NEXT:    srli a1, a1, 17
; RV32IZFBFMIN-NEXT:    or a0, a1, a0
; RV32IZFBFMIN-NEXT:    fmv.h.x fa0, a0
; RV32IZFBFMIN-NEXT:    ret
;
; RV64IZFBFMIN-LABEL: fsgnj_bf16:
; RV64IZFBFMIN:       # %bb.0:
; RV64IZFBFMIN-NEXT:    fmv.x.h a0, fa1
; RV64IZFBFMIN-NEXT:    lui a1, 1048568
; RV64IZFBFMIN-NEXT:    and a0, a0, a1
; RV64IZFBFMIN-NEXT:    fmv.x.h a1, fa0
; RV64IZFBFMIN-NEXT:    slli a1, a1, 49
; RV64IZFBFMIN-NEXT:    srli a1, a1, 49
; RV64IZFBFMIN-NEXT:    or a0, a1, a0
; RV64IZFBFMIN-NEXT:    fmv.h.x fa0, a0
; RV64IZFBFMIN-NEXT:    ret
  %1 = call bfloat @llvm.copysign.bf16(bfloat %a, bfloat %b)
  ret bfloat %1
}

define i32 @fneg_bf16(bfloat %a, bfloat %b) nounwind {
; CHECK-LABEL: fneg_bf16:
; 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:    fmv.x.h a0, fa5
; CHECK-NEXT:    lui a1, 1048568
; CHECK-NEXT:    xor a0, a0, a1
; CHECK-NEXT:    fmv.h.x fa4, a0
; CHECK-NEXT:    fcvt.s.bf16 fa4, fa4
; CHECK-NEXT:    fcvt.s.bf16 fa5, fa5
; 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_bf16(bfloat %a, bfloat %b) nounwind {
; RV32IZFBFMIN-LABEL: fsgnjn_bf16:
; RV32IZFBFMIN:       # %bb.0:
; 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:    fmv.x.h a0, fa5
; RV32IZFBFMIN-NEXT:    not a0, a0
; RV32IZFBFMIN-NEXT:    lui a1, 1048568
; RV32IZFBFMIN-NEXT:    and a0, a0, a1
; RV32IZFBFMIN-NEXT:    fmv.x.h a1, fa0
; RV32IZFBFMIN-NEXT:    slli a1, a1, 17
; RV32IZFBFMIN-NEXT:    srli a1, a1, 17
; RV32IZFBFMIN-NEXT:    or a0, a1, a0
; RV32IZFBFMIN-NEXT:    fmv.h.x fa0, a0
; RV32IZFBFMIN-NEXT:    ret
;
; RV64IZFBFMIN-LABEL: fsgnjn_bf16:
; RV64IZFBFMIN:       # %bb.0:
; 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:    fmv.x.h a0, fa5
; RV64IZFBFMIN-NEXT:    not a0, a0
; RV64IZFBFMIN-NEXT:    lui a1, 1048568
; RV64IZFBFMIN-NEXT:    and a0, a0, a1
; RV64IZFBFMIN-NEXT:    fmv.x.h a1, fa0
; RV64IZFBFMIN-NEXT:    slli a1, a1, 49
; RV64IZFBFMIN-NEXT:    srli a1, a1, 49
; RV64IZFBFMIN-NEXT:    or a0, a1, a0
; RV64IZFBFMIN-NEXT:    fmv.h.x fa0, a0
; 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_bf16(bfloat %a, bfloat %b) nounwind {
; RV32IZFBFMIN-LABEL: fabs_bf16:
; RV32IZFBFMIN:       # %bb.0:
; 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:    fmv.x.h a0, fa5
; RV32IZFBFMIN-NEXT:    slli a0, a0, 17
; RV32IZFBFMIN-NEXT:    srli a0, a0, 17
; RV32IZFBFMIN-NEXT:    fmv.h.x fa4, a0
; RV32IZFBFMIN-NEXT:    fcvt.s.bf16 fa5, fa5
; RV32IZFBFMIN-NEXT:    fcvt.s.bf16 fa4, fa4
; RV32IZFBFMIN-NEXT:    fadd.s fa5, fa4, fa5
; RV32IZFBFMIN-NEXT:    fcvt.bf16.s fa0, fa5
; RV32IZFBFMIN-NEXT:    ret
;
; RV64IZFBFMIN-LABEL: fabs_bf16:
; RV64IZFBFMIN:       # %bb.0:
; 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:    fmv.x.h a0, fa5
; RV64IZFBFMIN-NEXT:    slli a0, a0, 49
; RV64IZFBFMIN-NEXT:    srli a0, a0, 49
; RV64IZFBFMIN-NEXT:    fmv.h.x fa4, a0
; RV64IZFBFMIN-NEXT:    fcvt.s.bf16 fa5, fa5
; RV64IZFBFMIN-NEXT:    fcvt.s.bf16 fa4, fa4
; RV64IZFBFMIN-NEXT:    fadd.s fa5, fa4, fa5
; RV64IZFBFMIN-NEXT:    fcvt.bf16.s fa0, fa5
; RV64IZFBFMIN-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_bf16(bfloat %a, bfloat %b) nounwind {
; CHECK-LABEL: fmin_bf16:
; 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_bf16(bfloat %a, bfloat %b) nounwind {
; CHECK-LABEL: fmax_bf16:
; 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_bf16(bfloat %a, bfloat %b, bfloat %c) nounwind {
; CHECK-LABEL: fmadd_bf16:
; 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_bf16(bfloat %a, bfloat %b, bfloat %c) nounwind {
; CHECK-LABEL: fmsub_bf16:
; 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:    fmv.x.h a0, fa5
; CHECK-NEXT:    lui a1, 1048568
; CHECK-NEXT:    xor a0, a0, a1
; CHECK-NEXT:    fmv.h.x fa5, a0
; 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_bf16(bfloat %a, bfloat %b, bfloat %c) nounwind {
; CHECK-LABEL: fnmadd_bf16:
; 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:    fmv.x.h a0, fa5
; CHECK-NEXT:    lui a1, 1048568
; CHECK-NEXT:    xor a0, a0, a1
; CHECK-NEXT:    fmv.h.x fa5, a0
; CHECK-NEXT:    fmv.x.h a0, fa4
; CHECK-NEXT:    xor a0, a0, a1
; CHECK-NEXT:    fmv.h.x fa4, a0
; 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:    fmv.x.h a0, fa5
; CHECK-NEXT:    lui a1, 1048568
; CHECK-NEXT:    xor a0, a0, a1
; CHECK-NEXT:    fmv.h.x fa5, a0
; CHECK-NEXT:    fmv.x.h a0, fa4
; CHECK-NEXT:    xor a0, a0, a1
; CHECK-NEXT:    fmv.h.x fa4, a0
; 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:    fmv.x.h a0, fa5
; CHECK-NEXT:    lui a1, 1048568
; CHECK-NEXT:    xor a0, a0, a1
; CHECK-NEXT:    fmv.h.x fa0, a0
; 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:    fmv.x.h a0, fa5
; CHECK-NEXT:    lui a1, 1048568
; CHECK-NEXT:    xor a0, a0, a1
; CHECK-NEXT:    fmv.h.x fa0, a0
; 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_bf16(bfloat %a, bfloat %b, bfloat %c) nounwind {
; CHECK-LABEL: fnmsub_bf16:
; 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:    fmv.x.h a0, fa5
; CHECK-NEXT:    lui a1, 1048568
; CHECK-NEXT:    xor a0, a0, a1
; CHECK-NEXT:    fmv.h.x fa5, a0
; 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_bf16_2(bfloat %a, bfloat %b, bfloat %c) nounwind {
; CHECK-LABEL: fnmsub_bf16_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:    fmv.x.h a0, fa5
; CHECK-NEXT:    lui a1, 1048568
; CHECK-NEXT:    xor a0, a0, a1
; CHECK-NEXT:    fmv.h.x fa5, a0
; 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_bf16_contract(bfloat %a, bfloat %b, bfloat %c) nounwind {
; CHECK-LABEL: fmadd_bf16_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_bf16_contract(bfloat %a, bfloat %b, bfloat %c) nounwind {
; CHECK-LABEL: fmsub_bf16_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_bf16_contract(bfloat %a, bfloat %b, bfloat %c) nounwind {
; CHECK-LABEL: fnmadd_bf16_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:    fmv.x.h a0, fa5
; CHECK-NEXT:    lui a1, 1048568
; CHECK-NEXT:    xor a0, a0, a1
; CHECK-NEXT:    fmv.h.x fa5, a0
; 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_bf16_contract(bfloat %a, bfloat %b, bfloat %c) nounwind {
; CHECK-LABEL: fnmsub_bf16_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
}