[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