| ; 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: lui a0, 1048568 |
| ; CHECK-NEXT: fadd.s fa5, fa5, fa5 |
| ; CHECK-NEXT: fcvt.bf16.s fa5, fa5 |
| ; CHECK-NEXT: fmv.x.h a1, fa5 |
| ; CHECK-NEXT: xor a0, a1, a0 |
| ; 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: lui a0, 1048568 |
| ; RV32IZFBFMIN-NEXT: fadd.s fa5, fa4, fa5 |
| ; RV32IZFBFMIN-NEXT: fcvt.bf16.s fa5, fa5 |
| ; RV32IZFBFMIN-NEXT: fmv.x.h a1, fa5 |
| ; RV32IZFBFMIN-NEXT: not a1, a1 |
| ; RV32IZFBFMIN-NEXT: and a0, a1, a0 |
| ; 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: lui a0, 1048568 |
| ; RV64IZFBFMIN-NEXT: fadd.s fa5, fa4, fa5 |
| ; RV64IZFBFMIN-NEXT: fcvt.bf16.s fa5, fa5 |
| ; RV64IZFBFMIN-NEXT: fmv.x.h a1, fa5 |
| ; RV64IZFBFMIN-NEXT: not a1, a1 |
| ; RV64IZFBFMIN-NEXT: and a0, a1, a0 |
| ; 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: lui a0, 1048568 |
| ; CHECK-NEXT: fcvt.s.bf16 fa3, fa1 |
| ; CHECK-NEXT: fadd.s fa5, fa5, fa4 |
| ; CHECK-NEXT: fcvt.bf16.s fa5, fa5 |
| ; CHECK-NEXT: fmv.x.h a1, fa5 |
| ; CHECK-NEXT: xor a0, a1, a0 |
| ; CHECK-NEXT: fmv.h.x fa5, a0 |
| ; CHECK-NEXT: fcvt.s.bf16 fa5, fa5 |
| ; CHECK-NEXT: fcvt.s.bf16 fa4, fa0 |
| ; CHECK-NEXT: fmadd.s fa5, fa4, fa3, 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: fcvt.s.bf16 fa3, fa2 |
| ; CHECK-NEXT: lui a0, 1048568 |
| ; CHECK-NEXT: fadd.s fa5, fa5, fa4 |
| ; CHECK-NEXT: fadd.s fa4, fa3, fa4 |
| ; CHECK-NEXT: fcvt.bf16.s fa5, fa5 |
| ; CHECK-NEXT: fcvt.bf16.s fa4, fa4 |
| ; CHECK-NEXT: fmv.x.h a1, fa5 |
| ; CHECK-NEXT: fmv.x.h a2, fa4 |
| ; CHECK-NEXT: xor a1, a1, a0 |
| ; CHECK-NEXT: xor a0, a2, a0 |
| ; CHECK-NEXT: fmv.h.x fa5, 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: fcvt.s.bf16 fa3, fa2 |
| ; CHECK-NEXT: lui a0, 1048568 |
| ; CHECK-NEXT: fadd.s fa5, fa5, fa4 |
| ; CHECK-NEXT: fadd.s fa4, fa3, fa4 |
| ; CHECK-NEXT: fcvt.bf16.s fa5, fa5 |
| ; CHECK-NEXT: fcvt.bf16.s fa4, fa4 |
| ; CHECK-NEXT: fmv.x.h a1, fa5 |
| ; CHECK-NEXT: fmv.x.h a2, fa4 |
| ; CHECK-NEXT: xor a1, a1, a0 |
| ; CHECK-NEXT: xor a0, a2, a0 |
| ; CHECK-NEXT: fmv.h.x fa5, 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: lui a0, 1048568 |
| ; CHECK-NEXT: fcvt.s.bf16 fa3, fa2 |
| ; CHECK-NEXT: fadd.s fa5, fa5, fa4 |
| ; CHECK-NEXT: fcvt.bf16.s fa5, fa5 |
| ; CHECK-NEXT: fmv.x.h a1, fa5 |
| ; CHECK-NEXT: xor a0, a1, a0 |
| ; CHECK-NEXT: fmv.h.x fa5, a0 |
| ; CHECK-NEXT: fcvt.s.bf16 fa5, fa5 |
| ; CHECK-NEXT: fcvt.s.bf16 fa4, fa1 |
| ; CHECK-NEXT: fmadd.s fa5, fa5, fa4, fa3 |
| ; 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: lui a0, 1048568 |
| ; CHECK-NEXT: fcvt.s.bf16 fa3, fa2 |
| ; CHECK-NEXT: fadd.s fa5, fa5, fa4 |
| ; CHECK-NEXT: fcvt.bf16.s fa5, fa5 |
| ; CHECK-NEXT: fmv.x.h a1, fa5 |
| ; CHECK-NEXT: xor a0, a1, a0 |
| ; CHECK-NEXT: fmv.h.x fa5, a0 |
| ; CHECK-NEXT: fcvt.s.bf16 fa5, fa5 |
| ; CHECK-NEXT: fcvt.s.bf16 fa4, fa0 |
| ; CHECK-NEXT: fmadd.s fa5, fa4, fa5, fa3 |
| ; 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: fcvt.s.bf16 fa3, fa1 |
| ; CHECK-NEXT: fcvt.s.bf16 fa2, fa0 |
| ; CHECK-NEXT: fadd.s fa5, fa5, fa4 |
| ; CHECK-NEXT: fmul.s fa4, fa2, fa3 |
| ; CHECK-NEXT: fcvt.bf16.s fa5, fa5 |
| ; 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: fcvt.s.bf16 fa3, fa1 |
| ; CHECK-NEXT: fcvt.s.bf16 fa2, fa2 |
| ; CHECK-NEXT: lui a0, 1048568 |
| ; CHECK-NEXT: fadd.s fa5, fa5, fa4 |
| ; CHECK-NEXT: fadd.s fa3, fa3, fa4 |
| ; CHECK-NEXT: fadd.s fa4, fa2, fa4 |
| ; CHECK-NEXT: fcvt.bf16.s fa5, fa5 |
| ; CHECK-NEXT: fcvt.bf16.s fa3, fa3 |
| ; 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 a1, fa5 |
| ; CHECK-NEXT: xor a0, a1, a0 |
| ; 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: fcvt.s.bf16 fa3, fa1 |
| ; CHECK-NEXT: fadd.s fa5, fa5, fa4 |
| ; CHECK-NEXT: fadd.s fa4, fa3, fa4 |
| ; CHECK-NEXT: fcvt.bf16.s fa5, fa5 |
| ; 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 |
| } |