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