[llvm] [MIPS] Implement llvm.fminimum and llvm.fmaximum with f32/f64 (PR #89907)
YunQiang Su via llvm-commits
llvm-commits at lists.llvm.org
Sat Apr 27 00:57:01 PDT 2024
https://github.com/wzssyqa updated https://github.com/llvm/llvm-project/pull/89907
>From a3047c3e7893664b3eaa7be494ae4386f343b1af Mon Sep 17 00:00:00 2001
From: Cyan <cyanoxygen at aosc.io>
Date: Mon, 22 Apr 2024 17:01:39 +0800
Subject: [PATCH] [MIPS] Implement llvm.fminimum and llvm.fmaximum
The implementation used various checks against signed zeroes and NaNs to
ensure the correct value is returned.
---
llvm/lib/Target/Mips/MipsISelLowering.cpp | 99 +++++-
llvm/lib/Target/Mips/MipsISelLowering.h | 1 +
llvm/test/CodeGen/Mips/fminmaximum.ll | 377 ++++++++++++++++++++++
3 files changed, 476 insertions(+), 1 deletion(-)
create mode 100644 llvm/test/CodeGen/Mips/fminmaximum.ll
diff --git a/llvm/lib/Target/Mips/MipsISelLowering.cpp b/llvm/lib/Target/Mips/MipsISelLowering.cpp
index 7bc66b2d9f4b1b..27469957814009 100644
--- a/llvm/lib/Target/Mips/MipsISelLowering.cpp
+++ b/llvm/lib/Target/Mips/MipsISelLowering.cpp
@@ -447,7 +447,13 @@ MipsTargetLowering::MipsTargetLowering(const MipsTargetMachine &TM,
setOperationAction(ISD::FMA, MVT::f64, Expand);
setOperationAction(ISD::FREM, MVT::f32, Expand);
setOperationAction(ISD::FREM, MVT::f64, Expand);
-
+ if (Subtarget.isFP64bit() || Subtarget.isSingleFloat() ||
+ Subtarget.isFPXX()) {
+ setOperationAction(ISD::FMINIMUM, MVT::f32, Custom);
+ setOperationAction(ISD::FMAXIMUM, MVT::f32, Custom);
+ setOperationAction(ISD::FMINIMUM, MVT::f64, Custom);
+ setOperationAction(ISD::FMAXIMUM, MVT::f64, Custom);
+ }
// Lower f16 conversion operations into library calls
setOperationAction(ISD::FP16_TO_FP, MVT::f32, Expand);
setOperationAction(ISD::FP_TO_FP16, MVT::f32, Expand);
@@ -1258,6 +1264,9 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) const
case ISD::STORE: return lowerSTORE(Op, DAG);
case ISD::EH_DWARF_CFA: return lowerEH_DWARF_CFA(Op, DAG);
case ISD::FP_TO_SINT: return lowerFP_TO_SINT(Op, DAG);
+ case ISD::FMINIMUM:
+ case ISD::FMAXIMUM:
+ return lowerFMINIMUM_FMAXIMUM(Op, DAG);
}
return SDValue();
}
@@ -2516,6 +2525,94 @@ SDValue MipsTargetLowering::lowerFABS(SDValue Op, SelectionDAG &DAG) const {
return lowerFABS32(Op, DAG, Subtarget.hasExtractInsert());
}
+SDValue MipsTargetLowering::lowerFMINIMUM_FMAXIMUM(SDValue Op,
+ SelectionDAG &DAG) const {
+ // Get information about X and Y:
+ // VT of the operand, the operand itself and its length,
+ // The possibility of X or Y being a NaN.
+ EVT VT = Op.getValueType();
+ assert(
+ (VT == MVT::f32 || VT == MVT::f64) &&
+ "Unsupported float point type or operands are not floating point values");
+ // Used to compare an operand to zero.
+ EVT IVT = VT.changeTypeToInteger();
+ // Whether it is fminimum or fmaximum.
+ ISD::NodeType CmpOp = (ISD::NodeType)Op->getOpcode();
+ bool IsMaxOp = (CmpOp == ISD::FMAXIMUM);
+ SDValue X = Op->getOperand(0);
+ SDValue Y = Op->getOperand(1);
+ // The constructed DAG.
+ SDValue MinMax;
+ // Location of current node.
+ SDLoc Loc(Op);
+ // VT for the usage of SETCC op.
+ const TargetLowering &TLI = DAG.getTargetLoweringInfo();
+ EVT SetCCType =
+ TLI.getSetCCResultType(DAG.getDataLayout(), *DAG.getContext(), VT);
+
+ bool IsXNeverNaN = DAG.isKnownNeverNaN(X);
+ bool IsYNeverNaN = DAG.isKnownNeverNaN(Y);
+ bool NaNMightPresent = (!IsXNeverNaN || !IsYNeverNaN);
+ bool IsXNeverZero = DAG.isKnownNeverZeroFloat(X);
+ bool IsYNeverZero = DAG.isKnownNeverZeroFloat(Y);
+ bool ZeroMightPresent = (!IsXNeverZero || !IsYNeverZero);
+ // Note that on Pre-R6 targets fmin and fmax will be replaced with SetCC.
+ if (Subtarget.hasMips32r6() || Subtarget.hasMips64r6()) {
+ // We have matched min.s/d and max.s/d to their corresponding SDAG
+ // operations.
+ MinMax =
+ DAG.getNode((IsMaxOp ? ISD::FMAXNUM : ISD::FMINNUM), Loc, VT, X, Y);
+ } else {
+ // Otherwise, use SETCC.
+ SDValue SetCCCmp =
+ DAG.getSetCC(Loc, SetCCType, X, Y,
+ IsMaxOp ? ISD::CondCode::SETGT : ISD::CondCode::SETLT);
+ MinMax = DAG.getSelect(Loc, VT, SetCCCmp, X, Y);
+ }
+ // Add NaN related checks.
+ if (NaNMightPresent) {
+ // If either X or Y is NaN, return NaN.
+ APFloat APNaN = APFloat::getNaN(DAG.EVTToAPFloatSemantics(VT));
+ SDValue TstNaN = DAG.getSetCC(Loc, SetCCType, X, Y, ISD::CondCode::SETUO);
+ MinMax = DAG.getSelect(Loc, VT, TstNaN, DAG.getConstantFP(APNaN, Loc, VT),
+ MinMax);
+ }
+ // Add zero related checks.
+ if (ZeroMightPresent) {
+ // Check if both X and Y are zeroes.
+ // MIPS ignores signage of zeroes when comparing against zeroes, so -0.0 ==
+ // +0.0.
+ APFloat FPZero = APFloat::getZero(DAG.EVTToAPFloatSemantics(VT));
+ SDValue ConstFPZero = DAG.getConstantFP(FPZero, Loc, VT);
+ SDValue Res = DAG.getNode(ISD::FADD, Loc, VT, X, Y);
+ SDValue TstZeroes =
+ DAG.getSetCC(Loc, SetCCType, Res, ConstFPZero, ISD::CondCode::SETEQ);
+ SDValue IsXSigned;
+
+ if (VT.getSizeInBits() == 64 && Subtarget.isGP32bit()) {
+ // Extract the higher 32 bits, and compare like how 64-bit does.
+ SDValue ConstInt32Zero = DAG.getConstant(0, Loc, MVT::i32);
+ SDValue XHiInt = DAG.getNode(MipsISD::ExtractElementF64, Loc, MVT::i32, X,
+ DAG.getConstant(1, Loc, MVT::i32));
+ IsXSigned = DAG.getSetCC(Loc, SetCCType, XHiInt, ConstInt32Zero,
+ ISD::CondCode::SETLT);
+ } else {
+ SDValue ConstIntZero = DAG.getConstant(0, Loc, IVT);
+ // Check if X is signed.
+ // Bitcast X to an integer, and see if it is -(U)INT_MAX (compared to 0).
+ SDValue XInt = DAG.getNode(ISD::BITCAST, Loc, IVT, X);
+ IsXSigned = DAG.getSetCC(Loc, SetCCType, XInt, ConstIntZero,
+ ISD::CondCode::SETLT);
+ }
+ // Return Y if X and Y are both zeroes and X == -0.0, if op is max;
+ // Otherwise return Y.
+ SDValue XOrY = IsMaxOp ? DAG.getSelect(Loc, VT, IsXSigned, Y, X)
+ : DAG.getSelect(Loc, VT, IsXSigned, X, Y);
+ MinMax = DAG.getSelect(Loc, VT, TstZeroes, XOrY, MinMax);
+ }
+ return MinMax;
+}
+
SDValue MipsTargetLowering::
lowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const {
// check the depth
diff --git a/llvm/lib/Target/Mips/MipsISelLowering.h b/llvm/lib/Target/Mips/MipsISelLowering.h
index 84ad40d6bbbe26..055aea7e3e2e89 100644
--- a/llvm/lib/Target/Mips/MipsISelLowering.h
+++ b/llvm/lib/Target/Mips/MipsISelLowering.h
@@ -550,6 +550,7 @@ class TargetRegisterClass;
bool HasExtractInsert) const;
SDValue lowerFABS64(SDValue Op, SelectionDAG &DAG,
bool HasExtractInsert) const;
+ SDValue lowerFMINIMUM_FMAXIMUM(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const;
SDValue lowerEH_RETURN(SDValue Op, SelectionDAG &DAG) const;
diff --git a/llvm/test/CodeGen/Mips/fminmaximum.ll b/llvm/test/CodeGen/Mips/fminmaximum.ll
new file mode 100644
index 00000000000000..57dcb42d2a3730
--- /dev/null
+++ b/llvm/test/CodeGen/Mips/fminmaximum.ll
@@ -0,0 +1,377 @@
+; RUN: llc %s -mtriple=mipsel-linux-gnu -o - | \
+; RUN: FileCheck %s --check-prefix=MIPS32R5EL
+; RUN: llc %s -mtriple=mipsisa32r6el-linux-gnu -o - | \
+; RUN: FileCheck %s --check-prefix=MIPS32R6EL
+; RUN: llc %s -mtriple=mips64el-linux-gnuabi64 -o - | \
+; RUN: FileCheck %s --check-prefix=MIPS64R5EL
+; RUN: llc %s -mtriple=mipsisa64r6el-linux-gnuabi64 -o - | \
+; RUN: FileCheck %s --check-prefix=MIPS64R6EL
+
+define float @maxs(float %x, float %y) unnamed_addr {
+start:
+; MIPS32R5EL-LABEL: maxs
+; MIPS32R5EL: # %bb.0:
+; MIPS32R5EL-NEXT: mfc1 $1, $f12
+; MIPS32R5EL-NEXT: slti $1, $1, 0
+; MIPS32R5EL-NEXT: mov.s $f1, $f12
+; MIPS32R5EL-NEXT: movn.s $f1, $f14, $1
+; MIPS32R5EL-NEXT: c.ule.s $f12, $f14
+; MIPS32R5EL-NEXT: mov.s $f0, $f14
+; MIPS32R5EL-NEXT: movf.s $f0, $f12, $fcc0
+; MIPS32R5EL-NEXT: lui $1, %hi($CPI0_0)
+; MIPS32R5EL-NEXT: lwc1 $f2, %lo($CPI0_0)($1)
+; MIPS32R5EL-NEXT: c.un.s $f12, $f14
+; MIPS32R5EL-NEXT: movt.s $f0, $f2, $fcc0
+; MIPS32R5EL-NEXT: add.s $f2, $f12, $f14
+; MIPS32R5EL-NEXT: mtc1 $zero, $f3
+; MIPS32R5EL-NEXT: c.eq.s $f2, $f3
+; MIPS32R5EL-NEXT: jr $ra
+; MIPS32R5EL-NEXT: movt.s $f0, $f1, $fcc0
+;
+; MIPS64R5EL-LABEL: maxs
+; MIPS64R5EL: # %bb.0:
+; MIPS64R5EL-NEXT: mfc1 $1, $f12
+; MIPS64R5EL-NEXT: slti $1, $1, 0
+; MIPS64R5EL-NEXT: mov.s $f1, $f12
+; MIPS64R5EL-NEXT: movn.s $f1, $f13, $1
+; MIPS64R5EL-NEXT: c.ule.s $f12, $f13
+; MIPS64R5EL-NEXT: mov.s $f0, $f13
+; MIPS64R5EL-NEXT: movf.s $f0, $f12, $fcc0
+; MIPS64R5EL-NEXT: lui $1, %highest(.LCPI0_0)
+; MIPS64R5EL-NEXT: daddiu $1, $1, %higher(.LCPI0_0)
+; MIPS64R5EL-NEXT: dsll $1, $1, 16
+; MIPS64R5EL-NEXT: daddiu $1, $1, %hi(.LCPI0_0)
+; MIPS64R5EL-NEXT: dsll $1, $1, 16
+; MIPS64R5EL-NEXT: lwc1 $f2, %lo(.LCPI0_0)($1)
+; MIPS64R5EL-NEXT: c.un.s $f12, $f13
+; MIPS64R5EL-NEXT: movt.s $f0, $f2, $fcc0
+; MIPS64R5EL-NEXT: add.s $f2, $f12, $f13
+; MIPS64R5EL-NEXT: mtc1 $zero, $f3
+; MIPS64R5EL-NEXT: c.eq.s $f2, $f3
+; MIPS64R5EL-NEXT: jr $ra
+; MIPS64R5EL-NEXT: movt.s $f0, $f1, $fcc0
+;
+; MIPS32R6EL-LABEL: maxs
+; MIPS32R6EL: # %bb.0:
+; MIPS32R6EL-NEXT: max.s $f0, $f12, $f14
+; MIPS32R6EL-NEXT: cmp.un.s $f1, $f12, $f14
+; MIPS32R6EL-NEXT: lui $1, %hi($CPI0_0)
+; MIPS32R6EL-NEXT: lwc1 $f2, %lo($CPI0_0)($1)
+; MIPS32R6EL-NEXT: sel.s $f1, $f0, $f2
+; MIPS32R6EL-NEXT: mfc1 $1, $f12
+; MIPS32R6EL-NEXT: slti $1, $1, 0
+; MIPS32R6EL-NEXT: mtc1 $1, $f2
+; MIPS32R6EL-NEXT: sel.s $f2, $f12, $f14
+; MIPS32R6EL-NEXT: add.s $f0, $f12, $f14
+; MIPS32R6EL-NEXT: mtc1 $zero, $f3
+; MIPS32R6EL-NEXT: cmp.eq.s $f0, $f0, $f3
+; MIPS32R6EL-NEXT: jr $ra
+; MIPS32R6EL-NEXT: sel.s $f0, $f1, $f2
+;
+; MIPS64R6EL-LABEL: maxs
+; MIPS64R6EL: # %bb.0:
+; MIPS64R6EL-NEXT: mfc1 $1, $f12
+; MIPS64R6EL-NEXT: slti $1, $1, 0
+; MIPS64R6EL-NEXT: mtc1 $1, $f1
+; MIPS64R6EL-NEXT: sel.s $f1, $f12, $f13
+; MIPS64R6EL-NEXT: max.s $f0, $f12, $f13
+; MIPS64R6EL-NEXT: cmp.un.s $f2, $f12, $f13
+; MIPS64R6EL-NEXT: lui $1, %highest(.LCPI0_0)
+; MIPS64R6EL-NEXT: daddiu $1, $1, %higher(.LCPI0_0)
+; MIPS64R6EL-NEXT: dsll $1, $1, 16
+; MIPS64R6EL-NEXT: daddiu $1, $1, %hi(.LCPI0_0)
+; MIPS64R6EL-NEXT: dsll $1, $1, 16
+; MIPS64R6EL-NEXT: lwc1 $f3, %lo(.LCPI0_0)($1)
+; MIPS64R6EL-NEXT: sel.s $f2, $f0, $f3
+; MIPS64R6EL-NEXT: add.s $f0, $f12, $f13
+; MIPS64R6EL-NEXT: mtc1 $zero, $f3
+; MIPS64R6EL-NEXT: cmp.eq.s $f0, $f0, $f3
+; MIPS64R6EL-NEXT: jr $ra
+; MIPS64R6EL-NEXT: sel.s $f0, $f2, $f1
+
+ %0 = tail call float @llvm.maximum.f32(float %x, float %y)
+ ret float %0
+}
+
+define float @mins(float %x, float %y) unnamed_addr {
+start:
+; MIPS32R5EL-LABEL: mins
+; MIPS32R5EL: # %bb.0:
+; MIPS32R5EL-NEXT: mfc1 $1, $f12
+; MIPS32R5EL-NEXT: slti $1, $1, 0
+; MIPS32R5EL-NEXT: mov.s $f1, $f14
+; MIPS32R5EL-NEXT: movn.s $f1, $f12, $1
+; MIPS32R5EL-NEXT: c.olt.s $f12, $f14
+; MIPS32R5EL-NEXT: mov.s $f0, $f14
+; MIPS32R5EL-NEXT: movt.s $f0, $f12, $fcc0
+; MIPS32R5EL-NEXT: lui $1, %hi($CPI1_0)
+; MIPS32R5EL-NEXT: lwc1 $f2, %lo($CPI1_0)($1)
+; MIPS32R5EL-NEXT: c.un.s $f12, $f14
+; MIPS32R5EL-NEXT: movt.s $f0, $f2, $fcc0
+; MIPS32R5EL-NEXT: add.s $f2, $f12, $f14
+; MIPS32R5EL-NEXT: mtc1 $zero, $f3
+; MIPS32R5EL-NEXT: c.eq.s $f2, $f3
+; MIPS32R5EL-NEXT: jr $ra
+; MIPS32R5EL-NEXT: movt.s $f0, $f1, $fcc0
+;
+; MIPS64R5EL-LABEL: mins
+; MIPS64R5EL: # %bb.0:
+; MIPS64R5EL-NEXT: mfc1 $1, $f12
+; MIPS64R5EL-NEXT: slti $1, $1, 0
+; MIPS64R5EL-NEXT: mov.s $f1, $f13
+; MIPS64R5EL-NEXT: movn.s $f1, $f12, $1
+; MIPS64R5EL-NEXT: c.olt.s $f12, $f13
+; MIPS64R5EL-NEXT: mov.s $f0, $f13
+; MIPS64R5EL-NEXT: movt.s $f0, $f12, $fcc0
+; MIPS64R5EL-NEXT: lui $1, %highest(.LCPI1_0)
+; MIPS64R5EL-NEXT: daddiu $1, $1, %higher(.LCPI1_0)
+; MIPS64R5EL-NEXT: dsll $1, $1, 16
+; MIPS64R5EL-NEXT: daddiu $1, $1, %hi(.LCPI1_0)
+; MIPS64R5EL-NEXT: dsll $1, $1, 16
+; MIPS64R5EL-NEXT: lwc1 $f2, %lo(.LCPI1_0)($1)
+; MIPS64R5EL-NEXT: c.un.s $f12, $f13
+; MIPS64R5EL-NEXT: movt.s $f0, $f2, $fcc0
+; MIPS64R5EL-NEXT: add.s $f2, $f12, $f13
+; MIPS64R5EL-NEXT: mtc1 $zero, $f3
+; MIPS64R5EL-NEXT: c.eq.s $f2, $f3
+; MIPS64R5EL-NEXT: jr $ra
+; MIPS64R5EL-NEXT: movt.s $f0, $f1, $fcc0
+;
+; MIPS32R6EL-LABEL: mins
+; MIPS32R6EL: # %bb.0:
+; MIPS32R6EL-NEXT: min.s $f0, $f12, $f14
+; MIPS32R6EL-NEXT: cmp.un.s $f1, $f12, $f14
+; MIPS32R6EL-NEXT: lui $1, %hi($CPI1_0)
+; MIPS32R6EL-NEXT: lwc1 $f2, %lo($CPI1_0)($1)
+; MIPS32R6EL-NEXT: sel.s $f1, $f0, $f2
+; MIPS32R6EL-NEXT: mfc1 $1, $f12
+; MIPS32R6EL-NEXT: slti $1, $1, 0
+; MIPS32R6EL-NEXT: mtc1 $1, $f2
+; MIPS32R6EL-NEXT: sel.s $f2, $f14, $f12
+; MIPS32R6EL-NEXT: add.s $f0, $f12, $f14
+; MIPS32R6EL-NEXT: mtc1 $zero, $f3
+; MIPS32R6EL-NEXT: cmp.eq.s $f0, $f0, $f3
+; MIPS32R6EL-NEXT: jr $ra
+; MIPS32R6EL-NEXT: sel.s $f0, $f1, $f2
+;
+; MIPS64R6EL-LABEL: mins
+; MIPS64R6EL: # %bb.0:
+; MIPS64R6EL-NEXT: mfc1 $1, $f12
+; MIPS64R6EL-NEXT: slti $1, $1, 0
+; MIPS64R6EL-NEXT: mtc1 $1, $f1
+; MIPS64R6EL-NEXT: sel.s $f1, $f13, $f12
+; MIPS64R6EL-NEXT: min.s $f0, $f12, $f13
+; MIPS64R6EL-NEXT: cmp.un.s $f2, $f12, $f13
+; MIPS64R6EL-NEXT: lui $1, %highest(.LCPI1_0)
+; MIPS64R6EL-NEXT: daddiu $1, $1, %higher(.LCPI1_0)
+; MIPS64R6EL-NEXT: dsll $1, $1, 16
+; MIPS64R6EL-NEXT: daddiu $1, $1, %hi(.LCPI1_0)
+; MIPS64R6EL-NEXT: dsll $1, $1, 16
+; MIPS64R6EL-NEXT: lwc1 $f3, %lo(.LCPI1_0)($1)
+; MIPS64R6EL-NEXT: sel.s $f2, $f0, $f3
+; MIPS64R6EL-NEXT: add.s $f0, $f12, $f13
+; MIPS64R6EL-NEXT: mtc1 $zero, $f3
+; MIPS64R6EL-NEXT: cmp.eq.s $f0, $f0, $f3
+; MIPS64R6EL-NEXT: jr $ra
+; MIPS64R6EL-NEXT: sel.s $f0, $f2, $f1
+
+ %0 = tail call float @llvm.minimum.f32(float %x, float %y)
+ ret float %0
+}
+
+define double @maxd(double %x, double %y) unnamed_addr {
+start:
+; MIPS32R5EL-LABEL: maxd
+; MIPS32R5EL: # %bb.0
+; MIPS32R5EL-NEXT: mfc1 $1, $f13
+; MIPS32R5EL-NEXT: slti $1, $1, 0
+; MIPS32R5EL-NEXT: mov.d $f2, $f12
+; MIPS32R5EL-NEXT: movn.d $f2, $f14, $1
+; MIPS32R5EL-NEXT: c.ule.d $f12, $f14
+; MIPS32R5EL-NEXT: mov.d $f0, $f14
+; MIPS32R5EL-NEXT: movf.d $f0, $f12, $fcc0
+; MIPS32R5EL-NEXT: lui $1, %hi($CPI2_0)
+; MIPS32R5EL-NEXT: ldc1 $f4, %lo($CPI2_0)($1)
+; MIPS32R5EL-NEXT: c.un.d $f12, $f14
+; MIPS32R5EL-NEXT: movt.d $f0, $f4, $fcc0
+; MIPS32R5EL-NEXT: add.d $f4, $f12, $f14
+; MIPS32R5EL-NEXT: mtc1 $zero, $f6
+; MIPS32R5EL-NEXT: mtc1 $zero, $f7
+; MIPS32R5EL-NEXT: c.eq.d $f4, $f6
+; MIPS32R5EL-NEXT: jr $ra
+; MIPS32R5EL-NEXT: movt.d $f0, $f2, $fcc0
+;
+; MIPS64R5EL-LABEL: maxd
+; MIPS64R5EL: # %bb.0:
+; MIPS64R5EL-NEXT: dmfc1 $1, $f12
+; MIPS64R5EL-NEXT: slti $1, $1, 0
+; MIPS64R5EL-NEXT: mov.d $f1, $f12
+; MIPS64R5EL-NEXT: movn.d $f1, $f13, $1
+; MIPS64R5EL-NEXT: c.ule.d $f12, $f13
+; MIPS64R5EL-NEXT: mov.d $f0, $f13
+; MIPS64R5EL-NEXT: movf.d $f0, $f12, $fcc0
+; MIPS64R5EL-NEXT: lui $1, %highest(.LCPI2_0)
+; MIPS64R5EL-NEXT: daddiu $1, $1, %higher(.LCPI2_0)
+; MIPS64R5EL-NEXT: dsll $1, $1, 16
+; MIPS64R5EL-NEXT: daddiu $1, $1, %hi(.LCPI2_0)
+; MIPS64R5EL-NEXT: dsll $1, $1, 16
+; MIPS64R5EL-NEXT: ldc1 $f2, %lo(.LCPI2_0)($1)
+; MIPS64R5EL-NEXT: c.un.d $f12, $f13
+; MIPS64R5EL-NEXT: movt.d $f0, $f2, $fcc0
+; MIPS64R5EL-NEXT: add.d $f2, $f12, $f13
+; MIPS64R5EL-NEXT: dmtc1 $zero, $f3
+; MIPS64R5EL-NEXT: c.eq.d $f2, $f3
+; MIPS64R5EL-NEXT: jr $ra
+; MIPS64R5EL-NEXT: movt.d $f0, $f1, $fcc0
+;
+; MIPS32R6EL-LABEL: maxd
+; MIPS32R6EL: # %bb.0:
+; MIPS32R6EL-NEXT: max.d $f0, $f12, $f14
+; MIPS32R6EL-NEXT: cmp.un.d $f1, $f12, $f14
+; MIPS32R6EL-NEXT: mfc1 $1, $f1
+; MIPS32R6EL-NEXT: mtc1 $1, $f1
+; MIPS32R6EL-NEXT: mfhc1 $1, $f12
+; MIPS32R6EL-NEXT: slti $1, $1, 0
+; MIPS32R6EL-NEXT: lui $2, %hi($CPI2_0)
+; MIPS32R6EL-NEXT: ldc1 $f2, %lo($CPI2_0)($2)
+; MIPS32R6EL-NEXT: sel.d $f1, $f0, $f2
+; MIPS32R6EL-NEXT: mtc1 $1, $f2
+; MIPS32R6EL-NEXT: sel.d $f2, $f12, $f14
+; MIPS32R6EL-NEXT: add.d $f0, $f12, $f14
+; MIPS32R6EL-NEXT: mtc1 $zero, $f3
+; MIPS32R6EL-NEXT: mthc1 $zero, $f3
+; MIPS32R6EL-NEXT: cmp.eq.d $f0, $f0, $f3
+; MIPS32R6EL-NEXT: mfc1 $1, $f0
+; MIPS32R6EL-NEXT: mtc1 $1, $f0
+; MIPS32R6EL-NEXT: jr $ra
+; MIPS32R6EL-NEXT: sel.d $f0, $f1, $f2
+;
+; MIPS64R6EL-LABEL: maxd
+; MIPS64R6EL: # %bb.0:
+; MIPS64R6EL-NEXT: cmp.un.d $f0, $f12, $f13
+; MIPS64R6EL-NEXT: dmfc1 $1, $f12
+; MIPS64R6EL-NEXT: slti $1, $1, 0
+; MIPS64R6EL-NEXT: mtc1 $1, $f1
+; MIPS64R6EL-NEXT: sel.d $f1, $f12, $f13
+; MIPS64R6EL-NEXT: max.d $f2, $f12, $f13
+; MIPS64R6EL-NEXT: mfc1 $1, $f0
+; MIPS64R6EL-NEXT: mtc1 $1, $f3
+; MIPS64R6EL-NEXT: lui $1, %highest(.LCPI2_0)
+; MIPS64R6EL-NEXT: daddiu $1, $1, %higher(.LCPI2_0)
+; MIPS64R6EL-NEXT: dsll $1, $1, 16
+; MIPS64R6EL-NEXT: daddiu $1, $1, %hi(.LCPI2_0)
+; MIPS64R6EL-NEXT: dsll $1, $1, 16
+; MIPS64R6EL-NEXT: ldc1 $f0, %lo(.LCPI2_0)($1)
+; MIPS64R6EL-NEXT: sel.d $f3, $f2, $f0
+; MIPS64R6EL-NEXT: add.d $f0, $f12, $f13
+; MIPS64R6EL-NEXT: dmtc1 $zero, $f2
+; MIPS64R6EL-NEXT: cmp.eq.d $f0, $f0, $f2
+; MIPS64R6EL-NEXT: mfc1 $1, $f0
+; MIPS64R6EL-NEXT: mtc1 $1, $f0
+; MIPS64R6EL-NEXT: jr $ra
+; MIPS64R6EL-NEXT: sel.d $f0, $f3, $f1
+
+ %0 = tail call double @llvm.maximum.f64(double %x, double %y)
+ ret double %0
+}
+
+define double @mind(double %x, double %y) unnamed_addr {
+start:
+; MIPS32R5EL-LABEL: mind
+; MIPS32R5EL: # %bb.0:
+; MIPS32R5EL-NEXT: mfc1 $1, $f13
+; MIPS32R5EL-NEXT: slti $1, $1, 0
+; MIPS32R5EL-NEXT: mov.d $f2, $f14
+; MIPS32R5EL-NEXT: movn.d $f2, $f12, $1
+; MIPS32R5EL-NEXT: c.olt.d $f12, $f14
+; MIPS32R5EL-NEXT: mov.d $f0, $f14
+; MIPS32R5EL-NEXT: movt.d $f0, $f12, $fcc0
+; MIPS32R5EL-NEXT: lui $1, %hi($CPI3_0)
+; MIPS32R5EL-NEXT: ldc1 $f4, %lo($CPI3_0)($1)
+; MIPS32R5EL-NEXT: c.un.d $f12, $f14
+; MIPS32R5EL-NEXT: movt.d $f0, $f4, $fcc0
+; MIPS32R5EL-NEXT: add.d $f4, $f12, $f14
+; MIPS32R5EL-NEXT: mtc1 $zero, $f6
+; MIPS32R5EL-NEXT: mtc1 $zero, $f7
+; MIPS32R5EL-NEXT: c.eq.d $f4, $f6
+; MIPS32R5EL-NEXT: jr $ra
+; MIPS32R5EL-NEXT: movt.d $f0, $f2, $fcc0
+;
+; MIPS64R5EL-LABEL: mind
+; MIPS64R5EL: # %bb.0:
+; MIPS64R5EL-NEXT: dmfc1 $1, $f12
+; MIPS64R5EL-NEXT: slti $1, $1, 0
+; MIPS64R5EL-NEXT: mov.d $f1, $f13
+; MIPS64R5EL-NEXT: movn.d $f1, $f12, $1
+; MIPS64R5EL-NEXT: c.olt.d $f12, $f13
+; MIPS64R5EL-NEXT: mov.d $f0, $f13
+; MIPS64R5EL-NEXT: movt.d $f0, $f12, $fcc0
+; MIPS64R5EL-NEXT: lui $1, %highest(.LCPI3_0)
+; MIPS64R5EL-NEXT: daddiu $1, $1, %higher(.LCPI3_0)
+; MIPS64R5EL-NEXT: dsll $1, $1, 16
+; MIPS64R5EL-NEXT: daddiu $1, $1, %hi(.LCPI3_0)
+; MIPS64R5EL-NEXT: dsll $1, $1, 16
+; MIPS64R5EL-NEXT: ldc1 $f2, %lo(.LCPI3_0)($1)
+; MIPS64R5EL-NEXT: c.un.d $f12, $f13
+; MIPS64R5EL-NEXT: movt.d $f0, $f2, $fcc0
+; MIPS64R5EL-NEXT: add.d $f2, $f12, $f13
+; MIPS64R5EL-NEXT: dmtc1 $zero, $f3
+; MIPS64R5EL-NEXT: c.eq.d $f2, $f3
+; MIPS64R5EL-NEXT: jr $ra
+; MIPS64R5EL-NEXT: movt.d $f0, $f1, $fcc0
+;
+; MIPS32R6EL-LABEL: mind
+; MIPS32R6EL: # %bb.0:
+; MIPS32R6EL-NEXT: min.d $f0, $f12, $f14
+; MIPS32R6EL-NEXT: cmp.un.d $f1, $f12, $f14
+; MIPS32R6EL-NEXT: mfc1 $1, $f1
+; MIPS32R6EL-NEXT: mtc1 $1, $f1
+; MIPS32R6EL-NEXT: mfhc1 $1, $f12
+; MIPS32R6EL-NEXT: slti $1, $1, 0
+; MIPS32R6EL-NEXT: lui $2, %hi($CPI3_0)
+; MIPS32R6EL-NEXT: ldc1 $f2, %lo($CPI3_0)($2)
+; MIPS32R6EL-NEXT: sel.d $f1, $f0, $f2
+; MIPS32R6EL-NEXT: mtc1 $1, $f2
+; MIPS32R6EL-NEXT: sel.d $f2, $f14, $f12
+; MIPS32R6EL-NEXT: add.d $f0, $f12, $f14
+; MIPS32R6EL-NEXT: mtc1 $zero, $f3
+; MIPS32R6EL-NEXT: mthc1 $zero, $f3
+; MIPS32R6EL-NEXT: cmp.eq.d $f0, $f0, $f3
+; MIPS32R6EL-NEXT: mfc1 $1, $f0
+; MIPS32R6EL-NEXT: mtc1 $1, $f0
+; MIPS32R6EL-NEXT: jr $ra
+; MIPS32R6EL-NEXT: sel.d $f0, $f1, $f2
+;
+; MIPS64R6EL-LABEL: mind
+; MIPS64R6EL: # %bb.0:
+; MIPS64R6EL-NEXT: cmp.un.d $f0, $f12, $f13
+; MIPS64R6EL-NEXT: dmfc1 $1, $f12
+; MIPS64R6EL-NEXT: slti $1, $1, 0
+; MIPS64R6EL-NEXT: mtc1 $1, $f1
+; MIPS64R6EL-NEXT: sel.d $f1, $f13, $f12
+; MIPS64R6EL-NEXT: min.d $f2, $f12, $f13
+; MIPS64R6EL-NEXT: mfc1 $1, $f0
+; MIPS64R6EL-NEXT: mtc1 $1, $f3
+; MIPS64R6EL-NEXT: lui $1, %highest(.LCPI3_0)
+; MIPS64R6EL-NEXT: daddiu $1, $1, %higher(.LCPI3_0)
+; MIPS64R6EL-NEXT: dsll $1, $1, 16
+; MIPS64R6EL-NEXT: daddiu $1, $1, %hi(.LCPI3_0)
+; MIPS64R6EL-NEXT: dsll $1, $1, 16
+; MIPS64R6EL-NEXT: ldc1 $f0, %lo(.LCPI3_0)($1)
+; MIPS64R6EL-NEXT: sel.d $f3, $f2, $f0
+; MIPS64R6EL-NEXT: add.d $f0, $f12, $f13
+; MIPS64R6EL-NEXT: dmtc1 $zero, $f2
+; MIPS64R6EL-NEXT: cmp.eq.d $f0, $f0, $f2
+; MIPS64R6EL-NEXT: mfc1 $1, $f0
+; MIPS64R6EL-NEXT: mtc1 $1, $f0
+; MIPS64R6EL-NEXT: jr $ra
+; MIPS64R6EL-NEXT: sel.d $f0, $f3, $f1
+
+ %0 = tail call double @llvm.minimum.f64(double %x, double %y)
+ ret double %0
+}
+
+declare float @llvm.minimum.f32(float, float)
+declare float @llvm.maximum.f32(float, float)
+declare double @llvm.minimum.f64(double, double)
+declare double @llvm.maximum.f64(double, double)
More information about the llvm-commits
mailing list