llvm/llvm/test/CodeGen/RISCV/half-arith-strict.ll

; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=riscv32 -mattr=+zfh -verify-machineinstrs \
; RUN:   -disable-strictnode-mutation -target-abi ilp32f < %s | FileCheck %s
; RUN: llc -mtriple=riscv64 -mattr=+zfh -verify-machineinstrs \
; RUN:   -disable-strictnode-mutation -target-abi lp64f < %s | FileCheck %s
; RUN: llc -mtriple=riscv32 -mattr=+zhinx -verify-machineinstrs \
; RUN:   -disable-strictnode-mutation -target-abi ilp32 < %s \
; RUN:   | FileCheck -check-prefix=CHECK-ZHINX %s
; RUN: llc -mtriple=riscv64 -mattr=+zhinx -verify-machineinstrs \
; RUN:   -disable-strictnode-mutation -target-abi lp64 < %s \
; RUN:   | FileCheck -check-prefix=CHECK-ZHINX %s
; RUN: llc -mtriple=riscv32 -mattr=+zfhmin -verify-machineinstrs \
; RUN:   -disable-strictnode-mutation -target-abi ilp32f < %s \
; RUN:   | FileCheck -check-prefixes=CHECK-ZFHMIN,CHECK-ZFHMIN-RV32 %s
; RUN: llc -mtriple=riscv64 -mattr=+zfhmin -verify-machineinstrs \
; RUN:   -disable-strictnode-mutation -target-abi lp64f < %s \
; RUN:  | FileCheck -check-prefixes=CHECK-ZFHMIN,CHECK-ZFHMIN-RV64 %s
; RUN: llc -mtriple=riscv32 -mattr=+zhinxmin -verify-machineinstrs \
; RUN:   -disable-strictnode-mutation -target-abi ilp32 < %s \
; RUN:   | FileCheck -check-prefixes=CHECK-ZHINXMIN,CHECK-ZHINXMIN-RV32 %s
; RUN: llc -mtriple=riscv64 -mattr=+zhinxmin -verify-machineinstrs \
; RUN:   -disable-strictnode-mutation -target-abi lp64 < %s \
; RUN:   | FileCheck -check-prefixes=CHECK-ZHINXMIN,CHECK-ZHINXMIN-RV64 %s

; FIXME: We can't test without Zfh because soft promote legalization isn't
; implemented in SelectionDAG for STRICT nodes.

define half @fadd_h(half %a, half %b) nounwind strictfp {
; CHECK-LABEL: fadd_h:
; CHECK:       # %bb.0:
; CHECK-NEXT:    fadd.h fa0, fa0, fa1
; CHECK-NEXT:    ret
;
; CHECK-ZHINX-LABEL: fadd_h:
; CHECK-ZHINX:       # %bb.0:
; CHECK-ZHINX-NEXT:    fadd.h a0, a0, a1
; CHECK-ZHINX-NEXT:    ret
;
; CHECK-ZFHMIN-LABEL: fadd_h:
; CHECK-ZFHMIN:       # %bb.0:
; CHECK-ZFHMIN-NEXT:    fcvt.s.h fa5, fa1
; CHECK-ZFHMIN-NEXT:    fcvt.s.h fa4, fa0
; CHECK-ZFHMIN-NEXT:    fadd.s fa5, fa4, fa5
; CHECK-ZFHMIN-NEXT:    fcvt.h.s fa0, fa5
; CHECK-ZFHMIN-NEXT:    ret
;
; CHECK-ZHINXMIN-LABEL: fadd_h:
; CHECK-ZHINXMIN:       # %bb.0:
; CHECK-ZHINXMIN-NEXT:    fcvt.s.h a1, a1
; CHECK-ZHINXMIN-NEXT:    fcvt.s.h a0, a0
; CHECK-ZHINXMIN-NEXT:    fadd.s a0, a0, a1
; CHECK-ZHINXMIN-NEXT:    fcvt.h.s a0, a0
; CHECK-ZHINXMIN-NEXT:    ret
  %1 = call half @llvm.experimental.constrained.fadd.f16(half %a, half %b, metadata !"round.dynamic", metadata !"fpexcept.strict") strictfp
  ret half %1
}
declare half @llvm.experimental.constrained.fadd.f16(half, half, metadata, metadata)

define half @fsub_h(half %a, half %b) nounwind strictfp {
; CHECK-LABEL: fsub_h:
; CHECK:       # %bb.0:
; CHECK-NEXT:    fsub.h fa0, fa0, fa1
; CHECK-NEXT:    ret
;
; CHECK-ZHINX-LABEL: fsub_h:
; CHECK-ZHINX:       # %bb.0:
; CHECK-ZHINX-NEXT:    fsub.h a0, a0, a1
; CHECK-ZHINX-NEXT:    ret
;
; CHECK-ZFHMIN-LABEL: fsub_h:
; CHECK-ZFHMIN:       # %bb.0:
; CHECK-ZFHMIN-NEXT:    fcvt.s.h fa5, fa1
; CHECK-ZFHMIN-NEXT:    fcvt.s.h fa4, fa0
; CHECK-ZFHMIN-NEXT:    fsub.s fa5, fa4, fa5
; CHECK-ZFHMIN-NEXT:    fcvt.h.s fa0, fa5
; CHECK-ZFHMIN-NEXT:    ret
;
; CHECK-ZHINXMIN-LABEL: fsub_h:
; CHECK-ZHINXMIN:       # %bb.0:
; CHECK-ZHINXMIN-NEXT:    fcvt.s.h a1, a1
; CHECK-ZHINXMIN-NEXT:    fcvt.s.h a0, a0
; CHECK-ZHINXMIN-NEXT:    fsub.s a0, a0, a1
; CHECK-ZHINXMIN-NEXT:    fcvt.h.s a0, a0
; CHECK-ZHINXMIN-NEXT:    ret
  %1 = call half @llvm.experimental.constrained.fsub.f16(half %a, half %b, metadata !"round.dynamic", metadata !"fpexcept.strict") strictfp
  ret half %1
}
declare half @llvm.experimental.constrained.fsub.f16(half, half, metadata, metadata)

define half @fmul_h(half %a, half %b) nounwind strictfp {
; CHECK-LABEL: fmul_h:
; CHECK:       # %bb.0:
; CHECK-NEXT:    fmul.h fa0, fa0, fa1
; CHECK-NEXT:    ret
;
; CHECK-ZHINX-LABEL: fmul_h:
; CHECK-ZHINX:       # %bb.0:
; CHECK-ZHINX-NEXT:    fmul.h a0, a0, a1
; CHECK-ZHINX-NEXT:    ret
;
; CHECK-ZFHMIN-LABEL: fmul_h:
; CHECK-ZFHMIN:       # %bb.0:
; CHECK-ZFHMIN-NEXT:    fcvt.s.h fa5, fa1
; CHECK-ZFHMIN-NEXT:    fcvt.s.h fa4, fa0
; CHECK-ZFHMIN-NEXT:    fmul.s fa5, fa4, fa5
; CHECK-ZFHMIN-NEXT:    fcvt.h.s fa0, fa5
; CHECK-ZFHMIN-NEXT:    ret
;
; CHECK-ZHINXMIN-LABEL: fmul_h:
; CHECK-ZHINXMIN:       # %bb.0:
; CHECK-ZHINXMIN-NEXT:    fcvt.s.h a1, a1
; CHECK-ZHINXMIN-NEXT:    fcvt.s.h a0, a0
; CHECK-ZHINXMIN-NEXT:    fmul.s a0, a0, a1
; CHECK-ZHINXMIN-NEXT:    fcvt.h.s a0, a0
; CHECK-ZHINXMIN-NEXT:    ret
  %1 = call half @llvm.experimental.constrained.fmul.f16(half %a, half %b, metadata !"round.dynamic", metadata !"fpexcept.strict") strictfp
  ret half %1
}
declare half @llvm.experimental.constrained.fmul.f16(half, half, metadata, metadata)

define half @fdiv_h(half %a, half %b) nounwind strictfp {
; CHECK-LABEL: fdiv_h:
; CHECK:       # %bb.0:
; CHECK-NEXT:    fdiv.h fa0, fa0, fa1
; CHECK-NEXT:    ret
;
; CHECK-ZHINX-LABEL: fdiv_h:
; CHECK-ZHINX:       # %bb.0:
; CHECK-ZHINX-NEXT:    fdiv.h a0, a0, a1
; CHECK-ZHINX-NEXT:    ret
;
; CHECK-ZFHMIN-LABEL: fdiv_h:
; CHECK-ZFHMIN:       # %bb.0:
; CHECK-ZFHMIN-NEXT:    fcvt.s.h fa5, fa1
; CHECK-ZFHMIN-NEXT:    fcvt.s.h fa4, fa0
; CHECK-ZFHMIN-NEXT:    fdiv.s fa5, fa4, fa5
; CHECK-ZFHMIN-NEXT:    fcvt.h.s fa0, fa5
; CHECK-ZFHMIN-NEXT:    ret
;
; CHECK-ZHINXMIN-LABEL: fdiv_h:
; CHECK-ZHINXMIN:       # %bb.0:
; CHECK-ZHINXMIN-NEXT:    fcvt.s.h a1, a1
; CHECK-ZHINXMIN-NEXT:    fcvt.s.h a0, a0
; CHECK-ZHINXMIN-NEXT:    fdiv.s a0, a0, a1
; CHECK-ZHINXMIN-NEXT:    fcvt.h.s a0, a0
; CHECK-ZHINXMIN-NEXT:    ret
  %1 = call half @llvm.experimental.constrained.fdiv.f16(half %a, half %b, metadata !"round.dynamic", metadata !"fpexcept.strict") strictfp
  ret half %1
}
declare half @llvm.experimental.constrained.fdiv.f16(half, half, metadata, metadata)

define half @fsqrt_h(half %a) nounwind strictfp {
; CHECK-LABEL: fsqrt_h:
; CHECK:       # %bb.0:
; CHECK-NEXT:    fsqrt.h fa0, fa0
; CHECK-NEXT:    ret
;
; CHECK-ZHINX-LABEL: fsqrt_h:
; CHECK-ZHINX:       # %bb.0:
; CHECK-ZHINX-NEXT:    fsqrt.h a0, a0
; CHECK-ZHINX-NEXT:    ret
;
; CHECK-ZFHMIN-LABEL: fsqrt_h:
; CHECK-ZFHMIN:       # %bb.0:
; CHECK-ZFHMIN-NEXT:    fcvt.s.h fa5, fa0
; CHECK-ZFHMIN-NEXT:    fsqrt.s fa5, fa5
; CHECK-ZFHMIN-NEXT:    fcvt.h.s fa0, fa5
; CHECK-ZFHMIN-NEXT:    ret
;
; CHECK-ZHINXMIN-LABEL: fsqrt_h:
; CHECK-ZHINXMIN:       # %bb.0:
; CHECK-ZHINXMIN-NEXT:    fcvt.s.h a0, a0
; CHECK-ZHINXMIN-NEXT:    fsqrt.s a0, a0
; CHECK-ZHINXMIN-NEXT:    fcvt.h.s a0, a0
; CHECK-ZHINXMIN-NEXT:    ret
  %1 = call half @llvm.experimental.constrained.sqrt.f16(half %a, metadata !"round.dynamic", metadata !"fpexcept.strict") strictfp
  ret half %1
}
declare half @llvm.experimental.constrained.sqrt.f16(half, metadata, metadata)

; FIXME: fminnum/fmaxnum need libcalls to handle SNaN, but we don't have f16
; libcalls and don't support promotion yet.
;define half @fmin_h(half %a, half %b) nounwind strictfp {
;  %1 = call half @llvm.experimental.constrained.minnum.f16(half %a, half %b, metadata !"fpexcept.strict") strictfp
;  ret half %1
;}
;declare half @llvm.experimental.constrained.minnum.f16(half, half, metadata) strictfp
;
;define half @fmax_h(half %a, half %b) nounwind strictfp {
;  %1 = call half @llvm.experimental.constrained.maxnum.f16(half %a, half %b, metadata !"fpexcept.strict") strictfp
;  ret half %1
;}
;declare half @llvm.experimental.constrained.maxnum.f16(half, half, metadata) strictfp

define half @fmadd_h(half %a, half %b, half %c) nounwind strictfp {
; CHECK-LABEL: fmadd_h:
; CHECK:       # %bb.0:
; CHECK-NEXT:    fmadd.h fa0, fa0, fa1, fa2
; CHECK-NEXT:    ret
;
; CHECK-ZHINX-LABEL: fmadd_h:
; CHECK-ZHINX:       # %bb.0:
; CHECK-ZHINX-NEXT:    fmadd.h a0, a0, a1, a2
; CHECK-ZHINX-NEXT:    ret
;
; CHECK-ZFHMIN-LABEL: fmadd_h:
; CHECK-ZFHMIN:       # %bb.0:
; CHECK-ZFHMIN-NEXT:    fcvt.s.h fa5, fa2
; CHECK-ZFHMIN-NEXT:    fcvt.s.h fa4, fa1
; CHECK-ZFHMIN-NEXT:    fcvt.s.h fa3, fa0
; CHECK-ZFHMIN-NEXT:    fmadd.s fa5, fa3, fa4, fa5
; CHECK-ZFHMIN-NEXT:    fcvt.h.s fa0, fa5
; CHECK-ZFHMIN-NEXT:    ret
;
; CHECK-ZHINXMIN-LABEL: fmadd_h:
; CHECK-ZHINXMIN:       # %bb.0:
; CHECK-ZHINXMIN-NEXT:    fcvt.s.h a2, a2
; CHECK-ZHINXMIN-NEXT:    fcvt.s.h a1, a1
; CHECK-ZHINXMIN-NEXT:    fcvt.s.h a0, a0
; CHECK-ZHINXMIN-NEXT:    fmadd.s a0, a0, a1, a2
; CHECK-ZHINXMIN-NEXT:    fcvt.h.s a0, a0
; CHECK-ZHINXMIN-NEXT:    ret
  %1 = call half @llvm.experimental.constrained.fma.f16(half %a, half %b, half %c, metadata !"round.dynamic", metadata !"fpexcept.strict") strictfp
  ret half %1
}
declare half @llvm.experimental.constrained.fma.f16(half, half, half, metadata, metadata) strictfp

define half @fmsub_h(half %a, half %b, half %c) nounwind strictfp {
; CHECK-LABEL: fmsub_h:
; CHECK:       # %bb.0:
; CHECK-NEXT:    fmv.h.x fa5, zero
; CHECK-NEXT:    fadd.h fa5, fa2, fa5
; CHECK-NEXT:    fmsub.h fa0, fa0, fa1, fa5
; CHECK-NEXT:    ret
;
; CHECK-ZHINX-LABEL: fmsub_h:
; CHECK-ZHINX:       # %bb.0:
; CHECK-ZHINX-NEXT:    fadd.h a2, a2, zero
; CHECK-ZHINX-NEXT:    fmsub.h a0, a0, a1, a2
; CHECK-ZHINX-NEXT:    ret
;
; CHECK-ZFHMIN-LABEL: fmsub_h:
; CHECK-ZFHMIN:       # %bb.0:
; CHECK-ZFHMIN-NEXT:    fcvt.s.h fa5, fa2
; CHECK-ZFHMIN-NEXT:    fmv.w.x fa4, zero
; CHECK-ZFHMIN-NEXT:    fadd.s fa5, fa5, fa4
; CHECK-ZFHMIN-NEXT:    fcvt.h.s fa5, fa5
; CHECK-ZFHMIN-NEXT:    fmv.x.h a0, fa5
; CHECK-ZFHMIN-NEXT:    lui a1, 1048568
; CHECK-ZFHMIN-NEXT:    xor a0, a0, a1
; CHECK-ZFHMIN-NEXT:    fmv.h.x fa5, a0
; CHECK-ZFHMIN-NEXT:    fcvt.s.h fa5, fa5
; CHECK-ZFHMIN-NEXT:    fcvt.s.h fa4, fa1
; CHECK-ZFHMIN-NEXT:    fcvt.s.h fa3, fa0
; CHECK-ZFHMIN-NEXT:    fmadd.s fa5, fa3, fa4, fa5
; CHECK-ZFHMIN-NEXT:    fcvt.h.s fa0, fa5
; CHECK-ZFHMIN-NEXT:    ret
;
; CHECK-ZHINXMIN-LABEL: fmsub_h:
; CHECK-ZHINXMIN:       # %bb.0:
; CHECK-ZHINXMIN-NEXT:    fcvt.s.h a2, a2
; CHECK-ZHINXMIN-NEXT:    fadd.s a2, a2, zero
; CHECK-ZHINXMIN-NEXT:    fcvt.h.s a2, a2
; CHECK-ZHINXMIN-NEXT:    lui a3, 1048568
; CHECK-ZHINXMIN-NEXT:    xor a2, a2, a3
; CHECK-ZHINXMIN-NEXT:    fcvt.s.h a2, a2
; CHECK-ZHINXMIN-NEXT:    fcvt.s.h a1, a1
; CHECK-ZHINXMIN-NEXT:    fcvt.s.h a0, a0
; CHECK-ZHINXMIN-NEXT:    fmadd.s a0, a0, a1, a2
; CHECK-ZHINXMIN-NEXT:    fcvt.h.s a0, a0
; CHECK-ZHINXMIN-NEXT:    ret
  %c_ = fadd half 0.0, %c ; avoid negation using xor
  %negc = fneg half %c_
  %1 = call half @llvm.experimental.constrained.fma.f16(half %a, half %b, half %negc, metadata !"round.dynamic", metadata !"fpexcept.strict") strictfp
  ret half %1
}

define half @fnmadd_h(half %a, half %b, half %c) nounwind strictfp {
; CHECK-LABEL: fnmadd_h:
; CHECK:       # %bb.0:
; CHECK-NEXT:    fmv.h.x fa5, zero
; CHECK-NEXT:    fadd.h fa4, fa0, fa5
; CHECK-NEXT:    fadd.h fa5, fa2, fa5
; CHECK-NEXT:    fnmadd.h fa0, fa4, fa1, fa5
; CHECK-NEXT:    ret
;
; CHECK-ZHINX-LABEL: fnmadd_h:
; CHECK-ZHINX:       # %bb.0:
; CHECK-ZHINX-NEXT:    fadd.h a0, a0, zero
; CHECK-ZHINX-NEXT:    fadd.h a2, a2, zero
; CHECK-ZHINX-NEXT:    fnmadd.h a0, a0, a1, a2
; CHECK-ZHINX-NEXT:    ret
;
; CHECK-ZFHMIN-LABEL: fnmadd_h:
; CHECK-ZFHMIN:       # %bb.0:
; CHECK-ZFHMIN-NEXT:    fcvt.s.h fa5, fa0
; CHECK-ZFHMIN-NEXT:    fmv.w.x fa4, zero
; CHECK-ZFHMIN-NEXT:    fadd.s fa5, fa5, fa4
; CHECK-ZFHMIN-NEXT:    fcvt.h.s fa5, fa5
; CHECK-ZFHMIN-NEXT:    fcvt.s.h fa3, fa2
; CHECK-ZFHMIN-NEXT:    fadd.s fa4, fa3, fa4
; CHECK-ZFHMIN-NEXT:    fcvt.h.s fa4, fa4
; CHECK-ZFHMIN-NEXT:    fmv.x.h a0, fa5
; CHECK-ZFHMIN-NEXT:    lui a1, 1048568
; CHECK-ZFHMIN-NEXT:    xor a0, a0, a1
; CHECK-ZFHMIN-NEXT:    fmv.h.x fa5, a0
; CHECK-ZFHMIN-NEXT:    fmv.x.h a0, fa4
; CHECK-ZFHMIN-NEXT:    xor a0, a0, a1
; CHECK-ZFHMIN-NEXT:    fmv.h.x fa4, a0
; CHECK-ZFHMIN-NEXT:    fcvt.s.h fa4, fa4
; CHECK-ZFHMIN-NEXT:    fcvt.s.h fa5, fa5
; CHECK-ZFHMIN-NEXT:    fcvt.s.h fa3, fa1
; CHECK-ZFHMIN-NEXT:    fmadd.s fa5, fa5, fa3, fa4
; CHECK-ZFHMIN-NEXT:    fcvt.h.s fa0, fa5
; CHECK-ZFHMIN-NEXT:    ret
;
; CHECK-ZHINXMIN-LABEL: fnmadd_h:
; CHECK-ZHINXMIN:       # %bb.0:
; CHECK-ZHINXMIN-NEXT:    fcvt.s.h a0, a0
; CHECK-ZHINXMIN-NEXT:    fadd.s a0, a0, zero
; CHECK-ZHINXMIN-NEXT:    fcvt.h.s a0, a0
; CHECK-ZHINXMIN-NEXT:    fcvt.s.h a2, a2
; CHECK-ZHINXMIN-NEXT:    fadd.s a2, a2, zero
; CHECK-ZHINXMIN-NEXT:    fcvt.h.s a2, a2
; CHECK-ZHINXMIN-NEXT:    lui a3, 1048568
; CHECK-ZHINXMIN-NEXT:    xor a0, a0, a3
; CHECK-ZHINXMIN-NEXT:    xor a2, a2, a3
; CHECK-ZHINXMIN-NEXT:    fcvt.s.h a2, a2
; CHECK-ZHINXMIN-NEXT:    fcvt.s.h a0, a0
; CHECK-ZHINXMIN-NEXT:    fcvt.s.h a1, a1
; CHECK-ZHINXMIN-NEXT:    fmadd.s a0, a0, a1, a2
; CHECK-ZHINXMIN-NEXT:    fcvt.h.s a0, a0
; CHECK-ZHINXMIN-NEXT:    ret
  %a_ = fadd half 0.0, %a
  %c_ = fadd half 0.0, %c
  %nega = fneg half %a_
  %negc = fneg half %c_
  %1 = call half @llvm.experimental.constrained.fma.f16(half %nega, half %b, half %negc, metadata !"round.dynamic", metadata !"fpexcept.strict") strictfp
  ret half %1
}

define half @fnmadd_h_2(half %a, half %b, half %c) nounwind strictfp {
; CHECK-LABEL: fnmadd_h_2:
; CHECK:       # %bb.0:
; CHECK-NEXT:    fmv.h.x fa5, zero
; CHECK-NEXT:    fadd.h fa4, fa1, fa5
; CHECK-NEXT:    fadd.h fa5, fa2, fa5
; CHECK-NEXT:    fnmadd.h fa0, fa4, fa0, fa5
; CHECK-NEXT:    ret
;
; CHECK-ZHINX-LABEL: fnmadd_h_2:
; CHECK-ZHINX:       # %bb.0:
; CHECK-ZHINX-NEXT:    fadd.h a1, a1, zero
; CHECK-ZHINX-NEXT:    fadd.h a2, a2, zero
; CHECK-ZHINX-NEXT:    fnmadd.h a0, a1, a0, a2
; CHECK-ZHINX-NEXT:    ret
;
; CHECK-ZFHMIN-LABEL: fnmadd_h_2:
; CHECK-ZFHMIN:       # %bb.0:
; CHECK-ZFHMIN-NEXT:    fcvt.s.h fa5, fa1
; CHECK-ZFHMIN-NEXT:    fmv.w.x fa4, zero
; CHECK-ZFHMIN-NEXT:    fadd.s fa5, fa5, fa4
; CHECK-ZFHMIN-NEXT:    fcvt.h.s fa5, fa5
; CHECK-ZFHMIN-NEXT:    fcvt.s.h fa3, fa2
; CHECK-ZFHMIN-NEXT:    fadd.s fa4, fa3, fa4
; CHECK-ZFHMIN-NEXT:    fcvt.h.s fa4, fa4
; CHECK-ZFHMIN-NEXT:    fmv.x.h a0, fa5
; CHECK-ZFHMIN-NEXT:    lui a1, 1048568
; CHECK-ZFHMIN-NEXT:    xor a0, a0, a1
; CHECK-ZFHMIN-NEXT:    fmv.h.x fa5, a0
; CHECK-ZFHMIN-NEXT:    fmv.x.h a0, fa4
; CHECK-ZFHMIN-NEXT:    xor a0, a0, a1
; CHECK-ZFHMIN-NEXT:    fmv.h.x fa4, a0
; CHECK-ZFHMIN-NEXT:    fcvt.s.h fa4, fa4
; CHECK-ZFHMIN-NEXT:    fcvt.s.h fa5, fa5
; CHECK-ZFHMIN-NEXT:    fcvt.s.h fa3, fa0
; CHECK-ZFHMIN-NEXT:    fmadd.s fa5, fa3, fa5, fa4
; CHECK-ZFHMIN-NEXT:    fcvt.h.s fa0, fa5
; CHECK-ZFHMIN-NEXT:    ret
;
; CHECK-ZHINXMIN-LABEL: fnmadd_h_2:
; CHECK-ZHINXMIN:       # %bb.0:
; CHECK-ZHINXMIN-NEXT:    fcvt.s.h a1, a1
; CHECK-ZHINXMIN-NEXT:    fadd.s a1, a1, zero
; CHECK-ZHINXMIN-NEXT:    fcvt.h.s a1, a1
; CHECK-ZHINXMIN-NEXT:    fcvt.s.h a2, a2
; CHECK-ZHINXMIN-NEXT:    fadd.s a2, a2, zero
; CHECK-ZHINXMIN-NEXT:    fcvt.h.s a2, a2
; CHECK-ZHINXMIN-NEXT:    lui a3, 1048568
; CHECK-ZHINXMIN-NEXT:    xor a1, a1, a3
; CHECK-ZHINXMIN-NEXT:    xor a2, a2, a3
; CHECK-ZHINXMIN-NEXT:    fcvt.s.h a2, a2
; CHECK-ZHINXMIN-NEXT:    fcvt.s.h a1, a1
; CHECK-ZHINXMIN-NEXT:    fcvt.s.h a0, a0
; CHECK-ZHINXMIN-NEXT:    fmadd.s a0, a0, a1, a2
; CHECK-ZHINXMIN-NEXT:    fcvt.h.s a0, a0
; CHECK-ZHINXMIN-NEXT:    ret
  %b_ = fadd half 0.0, %b
  %c_ = fadd half 0.0, %c
  %negb = fneg half %b_
  %negc = fneg half %c_
  %1 = call half @llvm.experimental.constrained.fma.f16(half %a, half %negb, half %negc, metadata !"round.dynamic", metadata !"fpexcept.strict") strictfp
  ret half %1
}

define half @fnmsub_h(half %a, half %b, half %c) nounwind strictfp {
; CHECK-LABEL: fnmsub_h:
; CHECK:       # %bb.0:
; CHECK-NEXT:    fmv.h.x fa5, zero
; CHECK-NEXT:    fadd.h fa5, fa0, fa5
; CHECK-NEXT:    fnmsub.h fa0, fa5, fa1, fa2
; CHECK-NEXT:    ret
;
; CHECK-ZHINX-LABEL: fnmsub_h:
; CHECK-ZHINX:       # %bb.0:
; CHECK-ZHINX-NEXT:    fadd.h a0, a0, zero
; CHECK-ZHINX-NEXT:    fnmsub.h a0, a0, a1, a2
; CHECK-ZHINX-NEXT:    ret
;
; CHECK-ZFHMIN-LABEL: fnmsub_h:
; CHECK-ZFHMIN:       # %bb.0:
; CHECK-ZFHMIN-NEXT:    fcvt.s.h fa5, fa0
; CHECK-ZFHMIN-NEXT:    fmv.w.x fa4, zero
; CHECK-ZFHMIN-NEXT:    fadd.s fa5, fa5, fa4
; CHECK-ZFHMIN-NEXT:    fcvt.h.s fa5, fa5
; CHECK-ZFHMIN-NEXT:    fmv.x.h a0, fa5
; CHECK-ZFHMIN-NEXT:    lui a1, 1048568
; CHECK-ZFHMIN-NEXT:    xor a0, a0, a1
; CHECK-ZFHMIN-NEXT:    fmv.h.x fa5, a0
; CHECK-ZFHMIN-NEXT:    fcvt.s.h fa5, fa5
; CHECK-ZFHMIN-NEXT:    fcvt.s.h fa4, fa2
; CHECK-ZFHMIN-NEXT:    fcvt.s.h fa3, fa1
; CHECK-ZFHMIN-NEXT:    fmadd.s fa5, fa5, fa3, fa4
; CHECK-ZFHMIN-NEXT:    fcvt.h.s fa0, fa5
; CHECK-ZFHMIN-NEXT:    ret
;
; CHECK-ZHINXMIN-LABEL: fnmsub_h:
; CHECK-ZHINXMIN:       # %bb.0:
; CHECK-ZHINXMIN-NEXT:    fcvt.s.h a0, a0
; CHECK-ZHINXMIN-NEXT:    fadd.s a0, a0, zero
; CHECK-ZHINXMIN-NEXT:    fcvt.h.s a0, a0
; CHECK-ZHINXMIN-NEXT:    lui a3, 1048568
; CHECK-ZHINXMIN-NEXT:    xor a0, a0, a3
; CHECK-ZHINXMIN-NEXT:    fcvt.s.h a0, a0
; CHECK-ZHINXMIN-NEXT:    fcvt.s.h a2, a2
; CHECK-ZHINXMIN-NEXT:    fcvt.s.h a1, a1
; CHECK-ZHINXMIN-NEXT:    fmadd.s a0, a0, a1, a2
; CHECK-ZHINXMIN-NEXT:    fcvt.h.s a0, a0
; CHECK-ZHINXMIN-NEXT:    ret
  %a_ = fadd half 0.0, %a
  %nega = fneg half %a_
  %1 = call half @llvm.experimental.constrained.fma.f16(half %nega, half %b, half %c, metadata !"round.dynamic", metadata !"fpexcept.strict") strictfp
  ret half %1
}

define half @fnmsub_h_2(half %a, half %b, half %c) nounwind strictfp {
; CHECK-LABEL: fnmsub_h_2:
; CHECK:       # %bb.0:
; CHECK-NEXT:    fmv.h.x fa5, zero
; CHECK-NEXT:    fadd.h fa5, fa1, fa5
; CHECK-NEXT:    fnmsub.h fa0, fa5, fa0, fa2
; CHECK-NEXT:    ret
;
; CHECK-ZHINX-LABEL: fnmsub_h_2:
; CHECK-ZHINX:       # %bb.0:
; CHECK-ZHINX-NEXT:    fadd.h a1, a1, zero
; CHECK-ZHINX-NEXT:    fnmsub.h a0, a1, a0, a2
; CHECK-ZHINX-NEXT:    ret
;
; CHECK-ZFHMIN-LABEL: fnmsub_h_2:
; CHECK-ZFHMIN:       # %bb.0:
; CHECK-ZFHMIN-NEXT:    fcvt.s.h fa5, fa1
; CHECK-ZFHMIN-NEXT:    fmv.w.x fa4, zero
; CHECK-ZFHMIN-NEXT:    fadd.s fa5, fa5, fa4
; CHECK-ZFHMIN-NEXT:    fcvt.h.s fa5, fa5
; CHECK-ZFHMIN-NEXT:    fmv.x.h a0, fa5
; CHECK-ZFHMIN-NEXT:    lui a1, 1048568
; CHECK-ZFHMIN-NEXT:    xor a0, a0, a1
; CHECK-ZFHMIN-NEXT:    fmv.h.x fa5, a0
; CHECK-ZFHMIN-NEXT:    fcvt.s.h fa5, fa5
; CHECK-ZFHMIN-NEXT:    fcvt.s.h fa4, fa2
; CHECK-ZFHMIN-NEXT:    fcvt.s.h fa3, fa0
; CHECK-ZFHMIN-NEXT:    fmadd.s fa5, fa3, fa5, fa4
; CHECK-ZFHMIN-NEXT:    fcvt.h.s fa0, fa5
; CHECK-ZFHMIN-NEXT:    ret
;
; CHECK-ZHINXMIN-LABEL: fnmsub_h_2:
; CHECK-ZHINXMIN:       # %bb.0:
; CHECK-ZHINXMIN-NEXT:    fcvt.s.h a1, a1
; CHECK-ZHINXMIN-NEXT:    fadd.s a1, a1, zero
; CHECK-ZHINXMIN-NEXT:    fcvt.h.s a1, a1
; CHECK-ZHINXMIN-NEXT:    lui a3, 1048568
; CHECK-ZHINXMIN-NEXT:    xor a1, a1, a3
; CHECK-ZHINXMIN-NEXT:    fcvt.s.h a1, a1
; CHECK-ZHINXMIN-NEXT:    fcvt.s.h a2, a2
; CHECK-ZHINXMIN-NEXT:    fcvt.s.h a0, a0
; CHECK-ZHINXMIN-NEXT:    fmadd.s a0, a0, a1, a2
; CHECK-ZHINXMIN-NEXT:    fcvt.h.s a0, a0
; CHECK-ZHINXMIN-NEXT:    ret
  %b_ = fadd half 0.0, %b
  %negb = fneg half %b_
  %1 = call half @llvm.experimental.constrained.fma.f16(half %a, half %negb, half %c, metadata !"round.dynamic", metadata !"fpexcept.strict") strictfp
  ret half %1
}
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
; CHECK-ZFHMIN-RV32: {{.*}}
; CHECK-ZFHMIN-RV64: {{.*}}
; CHECK-ZHINXMIN-RV32: {{.*}}
; CHECK-ZHINXMIN-RV64: {{.*}}