// FP reciprocal operation
def : Pat<(fdiv fpimm1, FPR32:$src), (FRECIP_S $src)>;
+
+// fmadd.s: fj * fk + fa
+def : Pat<(fma FPR32:$fj, FPR32:$fk, FPR32:$fa), (FMADD_S $fj, $fk, $fa)>;
+
+// fmsub.s: fj * fk - fa
+def : Pat<(fma FPR32:$fj, FPR32:$fk, (fneg FPR32:$fa)),
+ (FMSUB_S FPR32:$fj, FPR32:$fk, FPR32:$fa)>;
+
+// fnmadd.s: -(fj * fk + fa)
+def : Pat<(fneg (fma FPR32:$fj, FPR32:$fk, FPR32:$fa)),
+ (FNMADD_S FPR32:$fj, FPR32:$fk, FPR32:$fa)>;
+
+// fnmadd.s: -fj * fk - fa (the nsz flag on the FMA)
+def : Pat<(fma_nsz (fneg FPR32:$fj), FPR32:$fk, (fneg FPR32:$fa)),
+ (FNMADD_S FPR32:$fj, FPR32:$fk, FPR32:$fa)>;
+
+// fnmsub.s: -fj * fk + fa
+def : Pat<(fma (fneg FPR32:$fj), FPR32:$fk, FPR32:$fa),
+ (FNMSUB_S FPR32:$fj, FPR32:$fk, FPR32:$fa)>;
} // Predicates = [HasBasicF]
let Predicates = [HasBasicF, IsLA64] in {
// FP reciprocal operation
def : Pat<(fdiv fpimm1, FPR64:$src), (FRECIP_D $src)>;
+
+// fmadd.d: fj * fk + fa
+def : Pat<(fma FPR64:$fj, FPR64:$fk, FPR64:$fa), (FMADD_D $fj, $fk, $fa)>;
+
+// fmsub.d: fj * fk - fa
+def : Pat<(fma FPR64:$fj, FPR64:$fk, (fneg FPR64:$fa)),
+ (FMSUB_D FPR64:$fj, FPR64:$fk, FPR64:$fa)>;
+
+// fnmadd.d: -(fj * fk + fa)
+def : Pat<(fneg (fma FPR64:$fj, FPR64:$fk, FPR64:$fa)),
+ (FNMADD_D FPR64:$fj, FPR64:$fk, FPR64:$fa)>;
+
+// fnmadd.d: -fj * fk - fa (the nsz flag on the FMA)
+def : Pat<(fma_nsz (fneg FPR64:$fj), FPR64:$fk, (fneg FPR64:$fa)),
+ (FNMADD_D FPR64:$fj, FPR64:$fk, FPR64:$fa)>;
+
+// fnmsub.d: -(fj * fk - fa)
+def : Pat<(fma (fneg FPR64:$fj), FPR64:$fk, FPR64:$fa),
+ (FNMSUB_D FPR64:$fj, FPR64:$fk, FPR64:$fa)>;
} // Predicates = [HasBasicD]
/// Floating point constants
setCondCodeAction(FPCCToExpand, MVT::f32, Expand);
setOperationAction(ISD::SELECT_CC, MVT::f32, Expand);
setOperationAction(ISD::BR_CC, MVT::f32, Expand);
+ setOperationAction(ISD::FMA, MVT::f32, Legal);
}
if (Subtarget.hasBasicD()) {
setCondCodeAction(FPCCToExpand, MVT::f64, Expand);
setOperationAction(ISD::BR_CC, MVT::f64, Expand);
setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand);
setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand);
+ setOperationAction(ISD::FMA, MVT::f64, Legal);
}
// Effectively disable jump table generation.
Result = Builder.CreateTrunc(Result, Builder.getInt32Ty());
return Result;
}
+
+bool LoongArchTargetLowering::isFMAFasterThanFMulAndFAdd(
+ const MachineFunction &MF, EVT VT) const {
+ VT = VT.getScalarType();
+
+ if (!VT.isSimple())
+ return false;
+
+ switch (VT.getSimpleVT().SimpleTy) {
+ case MVT::f32:
+ case MVT::f64:
+ return true;
+ default:
+ break;
+ }
+
+ return false;
+}
MachineFunction &MF,
unsigned Intrinsic) const override;
+ bool isFMAFasterThanFMulAndFAdd(const MachineFunction &MF,
+ EVT VT) const override;
+
private:
/// Target-specific function used to lower LoongArch calling conventions.
typedef bool LoongArchCCAssignFn(const DataLayout &DL, LoongArchABI::ABI ABI,
def BaseAddr : ComplexPattern<iPTR, 1, "SelectBaseAddr">;
+def fma_nsz : PatFrag<(ops node:$fj, node:$fk, node:$fa),
+ (fma node:$fj, node:$fk, node:$fa), [{
+ return N->getFlags().hasNoSignedZeros();
+}]>;
+
//===----------------------------------------------------------------------===//
// Instruction Formats
//===----------------------------------------------------------------------===//
--- /dev/null
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc --mtriple=loongarch32 --mattr=+d --fp-contract=fast < %s \
+; RUN: | FileCheck %s --check-prefix=LA32-CONTRACT-FAST
+; RUN: llc --mtriple=loongarch32 --mattr=+d --fp-contract=on < %s \
+; RUN: | FileCheck %s --check-prefix=LA32-CONTRACT-ON
+; RUN: llc --mtriple=loongarch32 --mattr=+d --fp-contract=off < %s \
+; RUN: | FileCheck %s --check-prefix=LA32-CONTRACT-OFF
+; RUN: llc --mtriple=loongarch64 --mattr=+d --fp-contract=fast < %s \
+; RUN: | FileCheck %s --check-prefix=LA64-CONTRACT-FAST
+; RUN: llc --mtriple=loongarch64 --mattr=+d --fp-contract=on < %s \
+; RUN: | FileCheck %s --check-prefix=LA64-CONTRACT-ON
+; RUN: llc --mtriple=loongarch64 --mattr=+d --fp-contract=off < %s \
+; RUN: | FileCheck %s --check-prefix=LA64-CONTRACT-OFF
+
+define double @fmadd_d(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fmadd_d:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: fmadd_d:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fmul.d $fa0, $fa0, $fa1
+; LA32-CONTRACT-ON-NEXT: fadd.d $fa0, $fa0, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: fmadd_d:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fmul.d $fa0, $fa0, $fa1
+; LA32-CONTRACT-OFF-NEXT: fadd.d $fa0, $fa0, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: fmadd_d:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: fmadd_d:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fmul.d $fa0, $fa0, $fa1
+; LA64-CONTRACT-ON-NEXT: fadd.d $fa0, $fa0, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: fmadd_d:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fmul.d $fa0, $fa0, $fa1
+; LA64-CONTRACT-OFF-NEXT: fadd.d $fa0, $fa0, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %mul = fmul double %a, %b
+ %add = fadd double %mul, %c
+ ret double %add
+}
+
+define double @fmsub_d(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fmsub_d:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: fmsub_d:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fmul.d $fa0, $fa0, $fa1
+; LA32-CONTRACT-ON-NEXT: fsub.d $fa0, $fa0, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: fmsub_d:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fmul.d $fa0, $fa0, $fa1
+; LA32-CONTRACT-OFF-NEXT: fsub.d $fa0, $fa0, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: fmsub_d:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: fmsub_d:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fmul.d $fa0, $fa0, $fa1
+; LA64-CONTRACT-ON-NEXT: fsub.d $fa0, $fa0, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: fmsub_d:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fmul.d $fa0, $fa0, $fa1
+; LA64-CONTRACT-OFF-NEXT: fsub.d $fa0, $fa0, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %mul = fmul double %a, %b
+ %sub = fsub double %mul, %c
+ ret double %sub
+}
+
+define double @fnmadd_d(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fnmadd_d:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: fnmadd_d:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fmul.d $fa0, $fa0, $fa1
+; LA32-CONTRACT-ON-NEXT: fadd.d $fa0, $fa0, $fa2
+; LA32-CONTRACT-ON-NEXT: fneg.d $fa0, $fa0
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: fnmadd_d:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fmul.d $fa0, $fa0, $fa1
+; LA32-CONTRACT-OFF-NEXT: fadd.d $fa0, $fa0, $fa2
+; LA32-CONTRACT-OFF-NEXT: fneg.d $fa0, $fa0
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: fnmadd_d:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: fnmadd_d:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fmul.d $fa0, $fa0, $fa1
+; LA64-CONTRACT-ON-NEXT: fadd.d $fa0, $fa0, $fa2
+; LA64-CONTRACT-ON-NEXT: fneg.d $fa0, $fa0
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: fnmadd_d:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fmul.d $fa0, $fa0, $fa1
+; LA64-CONTRACT-OFF-NEXT: fadd.d $fa0, $fa0, $fa2
+; LA64-CONTRACT-OFF-NEXT: fneg.d $fa0, $fa0
+; LA64-CONTRACT-OFF-NEXT: ret
+ %mul = fmul double %a, %b
+ %add = fadd double %mul, %c
+ %negadd = fneg double %add
+ ret double %negadd
+}
+
+define double @fnmadd_d_nsz(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fnmadd_d_nsz:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: fnmadd_d_nsz:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fneg.d $fa0, $fa0
+; LA32-CONTRACT-ON-NEXT: fmul.d $fa0, $fa0, $fa1
+; LA32-CONTRACT-ON-NEXT: fsub.d $fa0, $fa0, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: fnmadd_d_nsz:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fneg.d $fa0, $fa0
+; LA32-CONTRACT-OFF-NEXT: fmul.d $fa0, $fa0, $fa1
+; LA32-CONTRACT-OFF-NEXT: fsub.d $fa0, $fa0, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: fnmadd_d_nsz:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: fnmadd_d_nsz:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fneg.d $fa0, $fa0
+; LA64-CONTRACT-ON-NEXT: fmul.d $fa0, $fa0, $fa1
+; LA64-CONTRACT-ON-NEXT: fsub.d $fa0, $fa0, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: fnmadd_d_nsz:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fneg.d $fa0, $fa0
+; LA64-CONTRACT-OFF-NEXT: fmul.d $fa0, $fa0, $fa1
+; LA64-CONTRACT-OFF-NEXT: fsub.d $fa0, $fa0, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %nega = fneg nsz double %a
+ %negc = fneg nsz double %c
+ %mul = fmul nsz double %nega, %b
+ %add = fadd nsz double %mul, %negc
+ ret double %add
+}
+
+;; Check that fnmadd.d is not emitted.
+define double @not_fnmadd_d(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: not_fnmadd_d:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fneg.d $fa0, $fa0
+; LA32-CONTRACT-FAST-NEXT: fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: not_fnmadd_d:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fneg.d $fa0, $fa0
+; LA32-CONTRACT-ON-NEXT: fmul.d $fa0, $fa0, $fa1
+; LA32-CONTRACT-ON-NEXT: fsub.d $fa0, $fa0, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: not_fnmadd_d:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fneg.d $fa0, $fa0
+; LA32-CONTRACT-OFF-NEXT: fmul.d $fa0, $fa0, $fa1
+; LA32-CONTRACT-OFF-NEXT: fsub.d $fa0, $fa0, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: not_fnmadd_d:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fneg.d $fa0, $fa0
+; LA64-CONTRACT-FAST-NEXT: fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: not_fnmadd_d:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fneg.d $fa0, $fa0
+; LA64-CONTRACT-ON-NEXT: fmul.d $fa0, $fa0, $fa1
+; LA64-CONTRACT-ON-NEXT: fsub.d $fa0, $fa0, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: not_fnmadd_d:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fneg.d $fa0, $fa0
+; LA64-CONTRACT-OFF-NEXT: fmul.d $fa0, $fa0, $fa1
+; LA64-CONTRACT-OFF-NEXT: fsub.d $fa0, $fa0, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %nega = fneg double %a
+ %negc = fneg double %c
+ %mul = fmul double %nega, %b
+ %add = fadd double %mul, %negc
+ ret double %add
+}
+
+define double @fnmsub_d(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fnmsub_d:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: fnmsub_d:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fmul.d $fa0, $fa0, $fa1
+; LA32-CONTRACT-ON-NEXT: fsub.d $fa0, $fa2, $fa0
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: fnmsub_d:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fmul.d $fa0, $fa0, $fa1
+; LA32-CONTRACT-OFF-NEXT: fsub.d $fa0, $fa2, $fa0
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: fnmsub_d:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: fnmsub_d:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fmul.d $fa0, $fa0, $fa1
+; LA64-CONTRACT-ON-NEXT: fsub.d $fa0, $fa2, $fa0
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: fnmsub_d:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fmul.d $fa0, $fa0, $fa1
+; LA64-CONTRACT-OFF-NEXT: fsub.d $fa0, $fa2, $fa0
+; LA64-CONTRACT-OFF-NEXT: ret
+ %nega = fneg double %a
+ %mul = fmul double %nega, %b
+ %add = fadd double %mul, %c
+ ret double %add
+}
+
+define double @contract_fmadd_d(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: contract_fmadd_d:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: contract_fmadd_d:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: contract_fmadd_d:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: contract_fmadd_d:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: contract_fmadd_d:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: contract_fmadd_d:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %mul = fmul contract double %a, %b
+ %add = fadd contract double %mul, %c
+ ret double %add
+}
+
+define double @contract_fmsub_d(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: contract_fmsub_d:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: contract_fmsub_d:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: contract_fmsub_d:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: contract_fmsub_d:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: contract_fmsub_d:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: contract_fmsub_d:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %mul = fmul contract double %a, %b
+ %sub = fsub contract double %mul, %c
+ ret double %sub
+}
+
+define double @contract_fnmadd_d(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: contract_fnmadd_d:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: contract_fnmadd_d:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: contract_fnmadd_d:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: contract_fnmadd_d:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: contract_fnmadd_d:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: contract_fnmadd_d:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %mul = fmul contract double %a, %b
+ %add = fadd contract double %mul, %c
+ %negadd = fneg contract double %add
+ ret double %negadd
+}
+
+define double @contract_fnmadd_d_nsz(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: contract_fnmadd_d_nsz:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: contract_fnmadd_d_nsz:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: contract_fnmadd_d_nsz:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: contract_fnmadd_d_nsz:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: contract_fnmadd_d_nsz:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: contract_fnmadd_d_nsz:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %nega = fneg contract nsz double %a
+ %negc = fneg contract nsz double %c
+ %mul = fmul contract nsz double %nega, %b
+ %add = fadd contract nsz double %mul, %negc
+ ret double %add
+}
+
+;; Check that fnmadd.d is not emitted.
+define double @not_contract_fnmadd_d(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: not_contract_fnmadd_d:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fneg.d $fa0, $fa0
+; LA32-CONTRACT-FAST-NEXT: fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: not_contract_fnmadd_d:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fneg.d $fa0, $fa0
+; LA32-CONTRACT-ON-NEXT: fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: not_contract_fnmadd_d:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fneg.d $fa0, $fa0
+; LA32-CONTRACT-OFF-NEXT: fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: not_contract_fnmadd_d:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fneg.d $fa0, $fa0
+; LA64-CONTRACT-FAST-NEXT: fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: not_contract_fnmadd_d:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fneg.d $fa0, $fa0
+; LA64-CONTRACT-ON-NEXT: fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: not_contract_fnmadd_d:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fneg.d $fa0, $fa0
+; LA64-CONTRACT-OFF-NEXT: fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %nega = fneg contract double %a
+ %negc = fneg contract double %c
+ %mul = fmul contract double %nega, %b
+ %add = fadd contract double %mul, %negc
+ ret double %add
+}
+
+define double @contract_fnmsub_d(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: contract_fnmsub_d:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: contract_fnmsub_d:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: contract_fnmsub_d:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: contract_fnmsub_d:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: contract_fnmsub_d:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: contract_fnmsub_d:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %nega = fneg contract double %a
+ %mul = fmul contract double %nega, %b
+ %add = fadd contract double %mul, %c
+ ret double %add
+}
+
+declare double @llvm.fma.f64(double, double, double)
+
+define double @fmadd_d_intrinsics(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fmadd_d_intrinsics:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: fmadd_d_intrinsics:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: fmadd_d_intrinsics:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: fmadd_d_intrinsics:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: fmadd_d_intrinsics:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: fmadd_d_intrinsics:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %fma = call double @llvm.fma.f64(double %a, double %b, double %c)
+ ret double %fma
+}
+
+define double @fmsub_d_intrinsics(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fmsub_d_intrinsics:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: fmsub_d_intrinsics:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: fmsub_d_intrinsics:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: fmsub_d_intrinsics:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: fmsub_d_intrinsics:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: fmsub_d_intrinsics:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %negc = fneg double %c
+ %fma = call double @llvm.fma.f64(double %a, double %b, double %negc)
+ ret double %fma
+}
+
+define double @fnmadd_d_intrinsics(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fnmadd_d_intrinsics:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: fnmadd_d_intrinsics:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: fnmadd_d_intrinsics:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: fnmadd_d_intrinsics:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: fnmadd_d_intrinsics:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: fnmadd_d_intrinsics:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %fma = call double @llvm.fma.f64(double %a, double %b, double %c)
+ %neg = fneg double %fma
+ ret double %neg
+}
+
+define double @fnmadd_d_nsz_intrinsics(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fnmadd_d_nsz_intrinsics:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: fnmadd_d_nsz_intrinsics:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: fnmadd_d_nsz_intrinsics:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: fnmadd_d_nsz_intrinsics:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: fnmadd_d_nsz_intrinsics:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: fnmadd_d_nsz_intrinsics:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %nega = fneg double %a
+ %negc = fneg double %c
+ %fma = call nsz double @llvm.fma.f64(double %nega, double %b, double %negc)
+ ret double %fma
+}
+
+;; Check that fnmadd.d is not emitted.
+define double @not_fnmadd_d_intrinsics(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: not_fnmadd_d_intrinsics:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fneg.d $fa0, $fa0
+; LA32-CONTRACT-FAST-NEXT: fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: not_fnmadd_d_intrinsics:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fneg.d $fa0, $fa0
+; LA32-CONTRACT-ON-NEXT: fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: not_fnmadd_d_intrinsics:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fneg.d $fa0, $fa0
+; LA32-CONTRACT-OFF-NEXT: fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: not_fnmadd_d_intrinsics:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fneg.d $fa0, $fa0
+; LA64-CONTRACT-FAST-NEXT: fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: not_fnmadd_d_intrinsics:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fneg.d $fa0, $fa0
+; LA64-CONTRACT-ON-NEXT: fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: not_fnmadd_d_intrinsics:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fneg.d $fa0, $fa0
+; LA64-CONTRACT-OFF-NEXT: fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %nega = fneg double %a
+ %negc = fneg double %c
+ %fma = call double @llvm.fma.f64(double %nega, double %b, double %negc)
+ ret double %fma
+}
+
+define double @fnmsub_d_intrinsics(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fnmsub_d_intrinsics:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: fnmsub_d_intrinsics:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: fnmsub_d_intrinsics:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: fnmsub_d_intrinsics:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: fnmsub_d_intrinsics:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: fnmsub_d_intrinsics:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %nega = fneg double %a
+ %fma = call double @llvm.fma.f64(double %nega, double %b, double %c)
+ ret double %fma
+}
+
+define double @fnmsub_d_swap_intrinsics(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fnmsub_d_swap_intrinsics:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fnmsub.d $fa0, $fa1, $fa0, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: fnmsub_d_swap_intrinsics:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fnmsub.d $fa0, $fa1, $fa0, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: fnmsub_d_swap_intrinsics:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fnmsub.d $fa0, $fa1, $fa0, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: fnmsub_d_swap_intrinsics:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fnmsub.d $fa0, $fa1, $fa0, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: fnmsub_d_swap_intrinsics:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fnmsub.d $fa0, $fa1, $fa0, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: fnmsub_d_swap_intrinsics:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fnmsub.d $fa0, $fa1, $fa0, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %negb = fneg double %b
+ %fma = call double @llvm.fma.f64(double %a, double %negb, double %c)
+ ret double %fma
+}
+
+define double @fmadd_d_contract(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fmadd_d_contract:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: fmadd_d_contract:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: fmadd_d_contract:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: fmadd_d_contract:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: fmadd_d_contract:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: fmadd_d_contract:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %mul = fmul contract double %a, %b
+ %add = fadd contract double %mul, %c
+ ret double %add
+}
+
+define double @fmsub_d_contract(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fmsub_d_contract:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: fmsub_d_contract:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: fmsub_d_contract:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: fmsub_d_contract:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: fmsub_d_contract:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: fmsub_d_contract:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %mul = fmul contract double %a, %b
+ %sub = fsub contract double %mul, %c
+ ret double %sub
+}
+
+define double @fnmadd_d_contract(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fnmadd_d_contract:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: fnmadd_d_contract:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: fnmadd_d_contract:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: fnmadd_d_contract:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: fnmadd_d_contract:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: fnmadd_d_contract:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fnmadd.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %mul = fmul contract double %a, %b
+ %add = fadd contract double %mul, %c
+ %negadd = fneg contract double %add
+ ret double %negadd
+}
+
+define double @fnmsub_d_contract(double %a, double %b, double %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fnmsub_d_contract:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: fnmsub_d_contract:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: fnmsub_d_contract:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: fnmsub_d_contract:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: fnmsub_d_contract:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: fnmsub_d_contract:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fnmsub.d $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %mul = fmul contract double %a, %b
+ %sub = fsub contract double %c, %mul
+ ret double %sub
+}
--- /dev/null
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc --mtriple=loongarch32 --mattr=+f,-d --fp-contract=fast < %s \
+; RUN: | FileCheck %s --check-prefix=LA32-CONTRACT-FAST
+; RUN: llc --mtriple=loongarch32 --mattr=+f,-d --fp-contract=on < %s \
+; RUN: | FileCheck %s --check-prefix=LA32-CONTRACT-ON
+; RUN: llc --mtriple=loongarch32 --mattr=+f,-d --fp-contract=off < %s \
+; RUN: | FileCheck %s --check-prefix=LA32-CONTRACT-OFF
+; RUN: llc --mtriple=loongarch64 --mattr=+f,-d --fp-contract=fast < %s \
+; RUN: | FileCheck %s --check-prefix=LA64-CONTRACT-FAST
+; RUN: llc --mtriple=loongarch64 --mattr=+f,-d --fp-contract=on < %s \
+; RUN: | FileCheck %s --check-prefix=LA64-CONTRACT-ON
+; RUN: llc --mtriple=loongarch64 --mattr=+f,-d --fp-contract=off < %s \
+; RUN: | FileCheck %s --check-prefix=LA64-CONTRACT-OFF
+
+define float @fmadd_s(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fmadd_s:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: fmadd_s:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fmul.s $fa0, $fa0, $fa1
+; LA32-CONTRACT-ON-NEXT: fadd.s $fa0, $fa0, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: fmadd_s:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fmul.s $fa0, $fa0, $fa1
+; LA32-CONTRACT-OFF-NEXT: fadd.s $fa0, $fa0, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: fmadd_s:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: fmadd_s:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fmul.s $fa0, $fa0, $fa1
+; LA64-CONTRACT-ON-NEXT: fadd.s $fa0, $fa0, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: fmadd_s:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fmul.s $fa0, $fa0, $fa1
+; LA64-CONTRACT-OFF-NEXT: fadd.s $fa0, $fa0, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %mul = fmul float %a, %b
+ %add = fadd float %mul, %c
+ ret float %add
+}
+
+define float @fmsub_s(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fmsub_s:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: fmsub_s:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fmul.s $fa0, $fa0, $fa1
+; LA32-CONTRACT-ON-NEXT: fsub.s $fa0, $fa0, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: fmsub_s:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fmul.s $fa0, $fa0, $fa1
+; LA32-CONTRACT-OFF-NEXT: fsub.s $fa0, $fa0, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: fmsub_s:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: fmsub_s:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fmul.s $fa0, $fa0, $fa1
+; LA64-CONTRACT-ON-NEXT: fsub.s $fa0, $fa0, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: fmsub_s:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fmul.s $fa0, $fa0, $fa1
+; LA64-CONTRACT-OFF-NEXT: fsub.s $fa0, $fa0, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %mul = fmul float %a, %b
+ %sub = fsub float %mul, %c
+ ret float %sub
+}
+
+define float @fnmadd_s(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fnmadd_s:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: fnmadd_s:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fmul.s $fa0, $fa0, $fa1
+; LA32-CONTRACT-ON-NEXT: fadd.s $fa0, $fa0, $fa2
+; LA32-CONTRACT-ON-NEXT: fneg.s $fa0, $fa0
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: fnmadd_s:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fmul.s $fa0, $fa0, $fa1
+; LA32-CONTRACT-OFF-NEXT: fadd.s $fa0, $fa0, $fa2
+; LA32-CONTRACT-OFF-NEXT: fneg.s $fa0, $fa0
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: fnmadd_s:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: fnmadd_s:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fmul.s $fa0, $fa0, $fa1
+; LA64-CONTRACT-ON-NEXT: fadd.s $fa0, $fa0, $fa2
+; LA64-CONTRACT-ON-NEXT: fneg.s $fa0, $fa0
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: fnmadd_s:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fmul.s $fa0, $fa0, $fa1
+; LA64-CONTRACT-OFF-NEXT: fadd.s $fa0, $fa0, $fa2
+; LA64-CONTRACT-OFF-NEXT: fneg.s $fa0, $fa0
+; LA64-CONTRACT-OFF-NEXT: ret
+ %mul = fmul float %a, %b
+ %add = fadd float %mul, %c
+ %negadd = fneg float %add
+ ret float %negadd
+}
+
+define float @fnmadd_s_nsz(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fnmadd_s_nsz:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: fnmadd_s_nsz:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fneg.s $fa0, $fa0
+; LA32-CONTRACT-ON-NEXT: fmul.s $fa0, $fa0, $fa1
+; LA32-CONTRACT-ON-NEXT: fsub.s $fa0, $fa0, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: fnmadd_s_nsz:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fneg.s $fa0, $fa0
+; LA32-CONTRACT-OFF-NEXT: fmul.s $fa0, $fa0, $fa1
+; LA32-CONTRACT-OFF-NEXT: fsub.s $fa0, $fa0, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: fnmadd_s_nsz:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: fnmadd_s_nsz:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fneg.s $fa0, $fa0
+; LA64-CONTRACT-ON-NEXT: fmul.s $fa0, $fa0, $fa1
+; LA64-CONTRACT-ON-NEXT: fsub.s $fa0, $fa0, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: fnmadd_s_nsz:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fneg.s $fa0, $fa0
+; LA64-CONTRACT-OFF-NEXT: fmul.s $fa0, $fa0, $fa1
+; LA64-CONTRACT-OFF-NEXT: fsub.s $fa0, $fa0, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %nega = fneg nsz float %a
+ %negc = fneg nsz float %c
+ %mul = fmul nsz float %nega, %b
+ %add = fadd nsz float %mul, %negc
+ ret float %add
+}
+
+;; Check that fnmadd.s is not emitted.
+define float @not_fnmadd_s(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: not_fnmadd_s:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fneg.s $fa0, $fa0
+; LA32-CONTRACT-FAST-NEXT: fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: not_fnmadd_s:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fneg.s $fa0, $fa0
+; LA32-CONTRACT-ON-NEXT: fmul.s $fa0, $fa0, $fa1
+; LA32-CONTRACT-ON-NEXT: fsub.s $fa0, $fa0, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: not_fnmadd_s:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fneg.s $fa0, $fa0
+; LA32-CONTRACT-OFF-NEXT: fmul.s $fa0, $fa0, $fa1
+; LA32-CONTRACT-OFF-NEXT: fsub.s $fa0, $fa0, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: not_fnmadd_s:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fneg.s $fa0, $fa0
+; LA64-CONTRACT-FAST-NEXT: fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: not_fnmadd_s:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fneg.s $fa0, $fa0
+; LA64-CONTRACT-ON-NEXT: fmul.s $fa0, $fa0, $fa1
+; LA64-CONTRACT-ON-NEXT: fsub.s $fa0, $fa0, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: not_fnmadd_s:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fneg.s $fa0, $fa0
+; LA64-CONTRACT-OFF-NEXT: fmul.s $fa0, $fa0, $fa1
+; LA64-CONTRACT-OFF-NEXT: fsub.s $fa0, $fa0, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %nega = fneg float %a
+ %negc = fneg float %c
+ %mul = fmul float %nega, %b
+ %add = fadd float %mul, %negc
+ ret float %add
+}
+
+define float @fnmsub_s(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fnmsub_s:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: fnmsub_s:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fmul.s $fa0, $fa0, $fa1
+; LA32-CONTRACT-ON-NEXT: fsub.s $fa0, $fa2, $fa0
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: fnmsub_s:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fmul.s $fa0, $fa0, $fa1
+; LA32-CONTRACT-OFF-NEXT: fsub.s $fa0, $fa2, $fa0
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: fnmsub_s:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: fnmsub_s:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fmul.s $fa0, $fa0, $fa1
+; LA64-CONTRACT-ON-NEXT: fsub.s $fa0, $fa2, $fa0
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: fnmsub_s:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fmul.s $fa0, $fa0, $fa1
+; LA64-CONTRACT-OFF-NEXT: fsub.s $fa0, $fa2, $fa0
+; LA64-CONTRACT-OFF-NEXT: ret
+ %nega = fneg float %a
+ %mul = fmul float %nega, %b
+ %add = fadd float %mul, %c
+ ret float %add
+}
+
+define float @contract_fmadd_s(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: contract_fmadd_s:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: contract_fmadd_s:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: contract_fmadd_s:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: contract_fmadd_s:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: contract_fmadd_s:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: contract_fmadd_s:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %mul = fmul contract float %a, %b
+ %add = fadd contract float %mul, %c
+ ret float %add
+}
+
+define float @contract_fmsub_s(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: contract_fmsub_s:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: contract_fmsub_s:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: contract_fmsub_s:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: contract_fmsub_s:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: contract_fmsub_s:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: contract_fmsub_s:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %mul = fmul contract float %a, %b
+ %sub = fsub contract float %mul, %c
+ ret float %sub
+}
+
+define float @contract_fnmadd_s(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: contract_fnmadd_s:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: contract_fnmadd_s:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: contract_fnmadd_s:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: contract_fnmadd_s:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: contract_fnmadd_s:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: contract_fnmadd_s:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %mul = fmul contract float %a, %b
+ %add = fadd contract float %mul, %c
+ %negadd = fneg contract float %add
+ ret float %negadd
+}
+
+define float @contract_fnmadd_s_nsz(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: contract_fnmadd_s_nsz:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: contract_fnmadd_s_nsz:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: contract_fnmadd_s_nsz:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: contract_fnmadd_s_nsz:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: contract_fnmadd_s_nsz:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: contract_fnmadd_s_nsz:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %nega = fneg contract nsz float %a
+ %negc = fneg contract nsz float %c
+ %mul = fmul contract nsz float %nega, %b
+ %add = fadd contract nsz float %mul, %negc
+ ret float %add
+}
+
+;; Check that fnmadd.s is not emitted.
+define float @not_contract_fnmadd_s(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: not_contract_fnmadd_s:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fneg.s $fa0, $fa0
+; LA32-CONTRACT-FAST-NEXT: fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: not_contract_fnmadd_s:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fneg.s $fa0, $fa0
+; LA32-CONTRACT-ON-NEXT: fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: not_contract_fnmadd_s:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fneg.s $fa0, $fa0
+; LA32-CONTRACT-OFF-NEXT: fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: not_contract_fnmadd_s:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fneg.s $fa0, $fa0
+; LA64-CONTRACT-FAST-NEXT: fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: not_contract_fnmadd_s:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fneg.s $fa0, $fa0
+; LA64-CONTRACT-ON-NEXT: fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: not_contract_fnmadd_s:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fneg.s $fa0, $fa0
+; LA64-CONTRACT-OFF-NEXT: fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %nega = fneg contract float %a
+ %negc = fneg contract float %c
+ %mul = fmul contract float %nega, %b
+ %add = fadd contract float %mul, %negc
+ ret float %add
+}
+
+define float @contract_fnmsub_s(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: contract_fnmsub_s:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: contract_fnmsub_s:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: contract_fnmsub_s:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: contract_fnmsub_s:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: contract_fnmsub_s:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: contract_fnmsub_s:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %nega = fneg contract float %a
+ %mul = fmul contract float %nega, %b
+ %add = fadd contract float %mul, %c
+ ret float %add
+}
+
+declare float @llvm.fma.f64(float, float, float)
+
+define float @fmadd_s_intrinsics(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fmadd_s_intrinsics:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: fmadd_s_intrinsics:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: fmadd_s_intrinsics:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: fmadd_s_intrinsics:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: fmadd_s_intrinsics:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: fmadd_s_intrinsics:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %fma = call float @llvm.fma.f64(float %a, float %b, float %c)
+ ret float %fma
+}
+
+define float @fmsub_s_intrinsics(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fmsub_s_intrinsics:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: fmsub_s_intrinsics:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: fmsub_s_intrinsics:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: fmsub_s_intrinsics:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: fmsub_s_intrinsics:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: fmsub_s_intrinsics:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %negc = fneg float %c
+ %fma = call float @llvm.fma.f64(float %a, float %b, float %negc)
+ ret float %fma
+}
+
+define float @fnmadd_s_intrinsics(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fnmadd_s_intrinsics:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: fnmadd_s_intrinsics:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: fnmadd_s_intrinsics:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: fnmadd_s_intrinsics:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: fnmadd_s_intrinsics:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: fnmadd_s_intrinsics:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %fma = call float @llvm.fma.f64(float %a, float %b, float %c)
+ %neg = fneg float %fma
+ ret float %neg
+}
+
+define float @fnmadd_s_nsz_intrinsics(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fnmadd_s_nsz_intrinsics:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: fnmadd_s_nsz_intrinsics:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: fnmadd_s_nsz_intrinsics:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: fnmadd_s_nsz_intrinsics:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: fnmadd_s_nsz_intrinsics:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: fnmadd_s_nsz_intrinsics:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %nega = fneg float %a
+ %negc = fneg float %c
+ %fma = call nsz float @llvm.fma.f64(float %nega, float %b, float %negc)
+ ret float %fma
+}
+
+;; Check that fnmadd.s is not emitted.
+define float @not_fnmadd_s_intrinsics(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: not_fnmadd_s_intrinsics:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fneg.s $fa0, $fa0
+; LA32-CONTRACT-FAST-NEXT: fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: not_fnmadd_s_intrinsics:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fneg.s $fa0, $fa0
+; LA32-CONTRACT-ON-NEXT: fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: not_fnmadd_s_intrinsics:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fneg.s $fa0, $fa0
+; LA32-CONTRACT-OFF-NEXT: fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: not_fnmadd_s_intrinsics:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fneg.s $fa0, $fa0
+; LA64-CONTRACT-FAST-NEXT: fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: not_fnmadd_s_intrinsics:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fneg.s $fa0, $fa0
+; LA64-CONTRACT-ON-NEXT: fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: not_fnmadd_s_intrinsics:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fneg.s $fa0, $fa0
+; LA64-CONTRACT-OFF-NEXT: fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %nega = fneg float %a
+ %negc = fneg float %c
+ %fma = call float @llvm.fma.f64(float %nega, float %b, float %negc)
+ ret float %fma
+}
+
+define float @fnmsub_s_intrinsics(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fnmsub_s_intrinsics:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: fnmsub_s_intrinsics:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: fnmsub_s_intrinsics:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: fnmsub_s_intrinsics:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: fnmsub_s_intrinsics:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: fnmsub_s_intrinsics:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %nega = fneg float %a
+ %fma = call float @llvm.fma.f64(float %nega, float %b, float %c)
+ ret float %fma
+}
+
+define float @fnmsub_s_swap_intrinsics(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fnmsub_s_swap_intrinsics:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fnmsub.s $fa0, $fa1, $fa0, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: fnmsub_s_swap_intrinsics:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fnmsub.s $fa0, $fa1, $fa0, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: fnmsub_s_swap_intrinsics:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fnmsub.s $fa0, $fa1, $fa0, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: fnmsub_s_swap_intrinsics:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fnmsub.s $fa0, $fa1, $fa0, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: fnmsub_s_swap_intrinsics:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fnmsub.s $fa0, $fa1, $fa0, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: fnmsub_s_swap_intrinsics:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fnmsub.s $fa0, $fa1, $fa0, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %negb = fneg float %b
+ %fma = call float @llvm.fma.f64(float %a, float %negb, float %c)
+ ret float %fma
+}
+
+define float @fmadd_s_contract(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fmadd_s_contract:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: fmadd_s_contract:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: fmadd_s_contract:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: fmadd_s_contract:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: fmadd_s_contract:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: fmadd_s_contract:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %mul = fmul contract float %a, %b
+ %add = fadd contract float %mul, %c
+ ret float %add
+}
+
+define float @fmsub_s_contract(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fmsub_s_contract:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: fmsub_s_contract:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: fmsub_s_contract:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: fmsub_s_contract:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: fmsub_s_contract:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: fmsub_s_contract:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %mul = fmul contract float %a, %b
+ %sub = fsub contract float %mul, %c
+ ret float %sub
+}
+
+define float @fnmadd_s_contract(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fnmadd_s_contract:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: fnmadd_s_contract:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: fnmadd_s_contract:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: fnmadd_s_contract:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: fnmadd_s_contract:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: fnmadd_s_contract:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fnmadd.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %mul = fmul contract float %a, %b
+ %add = fadd contract float %mul, %c
+ %negadd = fneg contract float %add
+ ret float %negadd
+}
+
+define float @fnmsub_s_contract(float %a, float %b, float %c) nounwind {
+; LA32-CONTRACT-FAST-LABEL: fnmsub_s_contract:
+; LA32-CONTRACT-FAST: # %bb.0:
+; LA32-CONTRACT-FAST-NEXT: fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-FAST-NEXT: ret
+;
+; LA32-CONTRACT-ON-LABEL: fnmsub_s_contract:
+; LA32-CONTRACT-ON: # %bb.0:
+; LA32-CONTRACT-ON-NEXT: fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-ON-NEXT: ret
+;
+; LA32-CONTRACT-OFF-LABEL: fnmsub_s_contract:
+; LA32-CONTRACT-OFF: # %bb.0:
+; LA32-CONTRACT-OFF-NEXT: fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA32-CONTRACT-OFF-NEXT: ret
+;
+; LA64-CONTRACT-FAST-LABEL: fnmsub_s_contract:
+; LA64-CONTRACT-FAST: # %bb.0:
+; LA64-CONTRACT-FAST-NEXT: fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-FAST-NEXT: ret
+;
+; LA64-CONTRACT-ON-LABEL: fnmsub_s_contract:
+; LA64-CONTRACT-ON: # %bb.0:
+; LA64-CONTRACT-ON-NEXT: fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-ON-NEXT: ret
+;
+; LA64-CONTRACT-OFF-LABEL: fnmsub_s_contract:
+; LA64-CONTRACT-OFF: # %bb.0:
+; LA64-CONTRACT-OFF-NEXT: fnmsub.s $fa0, $fa0, $fa1, $fa2
+; LA64-CONTRACT-OFF-NEXT: ret
+ %mul = fmul contract float %a, %b
+ %sub = fsub contract float %c, %mul
+ ret float %sub
+}