[llvm] 4942978 - [RISCV] Add lowering for scalar fmaximum/fminimum.

Craig Topper via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 24 13:46:50 PDT 2023


Author: Craig Topper
Date: 2023-07-24T13:46:35-07:00
New Revision: 49429783b0f4fb9c6f2a25746fe90072e19eb38c

URL: https://github.com/llvm/llvm-project/commit/49429783b0f4fb9c6f2a25746fe90072e19eb38c
DIFF: https://github.com/llvm/llvm-project/commit/49429783b0f4fb9c6f2a25746fe90072e19eb38c.diff

LOG: [RISCV] Add lowering for scalar fmaximum/fminimum.

Unlike fmaxnum and fminnum, these operations propagate nan and
consider -0.0 to be less than +0.0.

Without Zfa, we don't have a single instruction for this. The
lowering I've used forces the other input to nan if one input
is a nan. If both inputs are nan, they get swapped. Then use
the fmax or fmin instruction.

New ISD nodes are needed because fmaxnum/fminnum to not define
the order of -0.0 and +0.0.

This lowering ensures the snans are quieted though that is probably not
required in default environment). Also ensures non-canonical nans
are canonicalized, though I'm also not sure that's needed.

Another option could be to use fmax/fmin and then overwrite the
result based on the inputs being nan, but I'm not sure we can do
that with any less code.

Future work will handle nonans FMF, and handling the case where
we can prove the input isn't nan.

This does fix the crash in #64022, but we need to do more work
to avoid scalarization.

Reviewed By: fakepaper56

Differential Revision: https://reviews.llvm.org/D156069

Added: 
    llvm/test/CodeGen/RISCV/double-maximum-minimum.ll
    llvm/test/CodeGen/RISCV/float-maximum-minimum.ll
    llvm/test/CodeGen/RISCV/half-maximum-minimum.ll

Modified: 
    llvm/lib/Target/RISCV/RISCVISelLowering.cpp
    llvm/lib/Target/RISCV/RISCVISelLowering.h
    llvm/lib/Target/RISCV/RISCVInstrInfoD.td
    llvm/lib/Target/RISCV/RISCVInstrInfoF.td
    llvm/lib/Target/RISCV/RISCVInstrInfoZfh.td
    llvm/test/Analysis/CostModel/RISCV/fp-min-max-abs.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index d65dd8ae2b2859..f49c5011607f99 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -423,6 +423,9 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
     // We need to custom promote this.
     if (Subtarget.is64Bit())
       setOperationAction(ISD::FPOWI, MVT::i32, Custom);
+
+    if (!Subtarget.hasStdExtZfa())
+      setOperationAction({ISD::FMAXIMUM, ISD::FMINIMUM}, MVT::f16, Custom);
   }
 
   if (Subtarget.hasStdExtFOrZfinx()) {
@@ -445,6 +448,8 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
 
     if (Subtarget.hasStdExtZfa())
       setOperationAction(ISD::FNEARBYINT, MVT::f32, Legal);
+    else
+      setOperationAction({ISD::FMAXIMUM, ISD::FMINIMUM}, MVT::f32, Custom);
   }
 
   if (Subtarget.hasStdExtFOrZfinx() && Subtarget.is64Bit())
@@ -461,6 +466,8 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
     } else {
       if (Subtarget.is64Bit())
         setOperationAction(FPRndMode, MVT::f64, Custom);
+
+      setOperationAction({ISD::FMAXIMUM, ISD::FMINIMUM}, MVT::f64, Custom);
     }
 
     setOperationAction(ISD::STRICT_FP_ROUND, MVT::f32, Legal);
@@ -4624,6 +4631,34 @@ SDValue RISCVTargetLowering::LowerIS_FPCLASS(SDValue Op,
                       ISD::CondCode::SETNE);
 }
 
+// Lower fmaximum and fminimum. Unlike our fmax and fmin instructions, these
+// operations propagate nans.
+static SDValue lowerFMAXIMUM_FMINIMUM(SDValue Op, SelectionDAG &DAG,
+                                      const RISCVSubtarget &Subtarget) {
+  SDLoc DL(Op);
+  EVT VT = Op.getValueType();
+
+  SDValue X = Op.getOperand(0);
+  SDValue Y = Op.getOperand(1);
+
+  MVT XLenVT = Subtarget.getXLenVT();
+
+  // If X is a nan, replace Y with X. If Y is a nan, replace X with Y. This
+  // ensures that when one input is a nan, the other will also be a nan allowing
+  // the nan to propagate. If both inputs are nan, this will swap the inputs
+  // which is harmless.
+  // FIXME: Handle nonans FMF and use isKnownNeverNaN.
+  SDValue XIsNonNan = DAG.getSetCC(DL, XLenVT, X, X, ISD::SETOEQ);
+  SDValue NewY = DAG.getSelect(DL, VT, XIsNonNan, Y, X);
+
+  SDValue YIsNonNan = DAG.getSetCC(DL, XLenVT, Y, Y, ISD::SETOEQ);
+  SDValue NewX = DAG.getSelect(DL, VT, YIsNonNan, X, Y);
+
+  unsigned Opc =
+      Op.getOpcode() == ISD::FMAXIMUM ? RISCVISD::FMAX : RISCVISD::FMIN;
+  return DAG.getNode(Opc, DL, VT, NewX, NewY);
+}
+
 /// Get a RISCV target specified VL op for a given SDNode.
 static unsigned getRISCVVLOp(SDValue Op) {
 #define OP_CASE(NODE)                                                          \
@@ -4948,6 +4983,9 @@ SDValue RISCVTargetLowering::LowerOperation(SDValue Op,
     }
     return SDValue();
   }
+  case ISD::FMAXIMUM:
+  case ISD::FMINIMUM:
+    return lowerFMAXIMUM_FMINIMUM(Op, DAG, Subtarget);
   case ISD::FP_EXTEND: {
     SDLoc DL(Op);
     EVT VT = Op.getValueType();
@@ -16054,6 +16092,8 @@ const char *RISCVTargetLowering::getTargetNodeName(unsigned Opcode) const {
   NODE_NAME_CASE(FP_EXTEND_BF16)
   NODE_NAME_CASE(FROUND)
   NODE_NAME_CASE(FPCLASS)
+  NODE_NAME_CASE(FMAX)
+  NODE_NAME_CASE(FMIN)
   NODE_NAME_CASE(READ_CYCLE_WIDE)
   NODE_NAME_CASE(BREV8)
   NODE_NAME_CASE(ORC_B)

diff  --git a/llvm/lib/Target/RISCV/RISCVISelLowering.h b/llvm/lib/Target/RISCV/RISCVISelLowering.h
index ec90e3c0cdcdde..164ded95a1b5c3 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.h
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.h
@@ -122,6 +122,10 @@ enum NodeType : unsigned {
   FROUND,
 
   FPCLASS,
+
+  // Floating point fmax and fmin matching the RISC-V instruction semantics.
+  FMAX, FMIN,
+
   // READ_CYCLE_WIDE - A read of the 64-bit cycle CSR on a 32-bit target
   // (returns (Lo, Hi)). It takes a chain operand.
   READ_CYCLE_WIDE,

diff  --git a/llvm/lib/Target/RISCV/RISCVInstrInfoD.td b/llvm/lib/Target/RISCV/RISCVInstrInfoD.td
index 61897e9024e2f0..7a79e3ca6a2f14 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoD.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoD.td
@@ -386,6 +386,8 @@ def : Pat<(fneg (any_fma_nsz FPR64IN32X:$rs1, FPR64IN32X:$rs2, FPR64IN32X:$rs3))
 foreach Ext = DExts in {
   defm : PatFprFpr_m<fminnum, FMIN_D, Ext>;
   defm : PatFprFpr_m<fmaxnum, FMAX_D, Ext>;
+  defm : PatFprFpr_m<riscv_fmin, FMIN_D, Ext>;
+  defm : PatFprFpr_m<riscv_fmax, FMAX_D, Ext>;
 }
 
 /// Setcc

diff  --git a/llvm/lib/Target/RISCV/RISCVInstrInfoF.td b/llvm/lib/Target/RISCV/RISCVInstrInfoF.td
index 199436bbc4ab8d..290c03defc5ff3 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoF.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoF.td
@@ -51,6 +51,9 @@ def riscv_fcvt_x
 def riscv_fcvt_xu
     : SDNode<"RISCVISD::FCVT_XU", SDT_RISCVFCVT_X>;
 
+def riscv_fmin : SDNode<"RISCVISD::FMIN", SDTFPBinOp>;
+def riscv_fmax : SDNode<"RISCVISD::FMAX", SDTFPBinOp>;
+
 def riscv_strict_fcvt_w_rv64
     : SDNode<"RISCVISD::STRICT_FCVT_W_RV64", SDT_RISCVFCVT_W_RV64,
              [SDNPHasChain]>;
@@ -555,6 +558,8 @@ def : Pat<(fneg (any_fma_nsz FPR32INX:$rs1, FPR32INX:$rs2, FPR32INX:$rs3)),
 foreach Ext = FExts in {
   defm : PatFprFpr_m<fminnum, FMIN_S, Ext>;
   defm : PatFprFpr_m<fmaxnum, FMAX_S, Ext>;
+  defm : PatFprFpr_m<riscv_fmin, FMIN_S, Ext>;
+  defm : PatFprFpr_m<riscv_fmax, FMAX_S, Ext>;
 }
 
 /// Setcc

diff  --git a/llvm/lib/Target/RISCV/RISCVInstrInfoZfh.td b/llvm/lib/Target/RISCV/RISCVInstrInfoZfh.td
index 5dc02e5fa9f9e9..810775a782412d 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoZfh.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoZfh.td
@@ -348,6 +348,8 @@ def : Pat<(fneg (any_fma_nsz FPR16INX:$rs1, FPR16INX:$rs2, FPR16INX:$rs3)),
 foreach Ext = ZfhExts in {
   defm : PatFprFpr_m<fminnum, FMIN_H, Ext>;
   defm : PatFprFpr_m<fmaxnum, FMAX_H, Ext>;
+  defm : PatFprFpr_m<riscv_fmin, FMIN_H, Ext>;
+  defm : PatFprFpr_m<riscv_fmax, FMAX_H, Ext>;
 }
 
 /// Setcc

diff  --git a/llvm/test/Analysis/CostModel/RISCV/fp-min-max-abs.ll b/llvm/test/Analysis/CostModel/RISCV/fp-min-max-abs.ll
index d6a6e0c171a2fb..0ec875f6483705 100644
--- a/llvm/test/Analysis/CostModel/RISCV/fp-min-max-abs.ll
+++ b/llvm/test/Analysis/CostModel/RISCV/fp-min-max-abs.ll
@@ -157,21 +157,21 @@ define void @maxnum() {
 
 define void @minimum() {
 ; CHECK-LABEL: 'minimum'
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 10 for instruction: %1 = call float @llvm.minimum.f32(float undef, float undef)
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 23 for instruction: %2 = call <2 x float> @llvm.minimum.v2f32(<2 x float> undef, <2 x float> undef)
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 47 for instruction: %3 = call <4 x float> @llvm.minimum.v4f32(<4 x float> undef, <4 x float> undef)
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 95 for instruction: %4 = call <8 x float> @llvm.minimum.v8f32(<8 x float> undef, <8 x float> undef)
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 191 for instruction: %5 = call <16 x float> @llvm.minimum.v16f32(<16 x float> undef, <16 x float> undef)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 2 for instruction: %1 = call float @llvm.minimum.f32(float undef, float undef)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 7 for instruction: %2 = call <2 x float> @llvm.minimum.v2f32(<2 x float> undef, <2 x float> undef)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 15 for instruction: %3 = call <4 x float> @llvm.minimum.v4f32(<4 x float> undef, <4 x float> undef)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 31 for instruction: %4 = call <8 x float> @llvm.minimum.v8f32(<8 x float> undef, <8 x float> undef)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 63 for instruction: %5 = call <16 x float> @llvm.minimum.v16f32(<16 x float> undef, <16 x float> undef)
 ; CHECK-NEXT:  Cost Model: Invalid cost for instruction: %6 = call <vscale x 1 x float> @llvm.minimum.nxv1f32(<vscale x 1 x float> undef, <vscale x 1 x float> undef)
 ; CHECK-NEXT:  Cost Model: Invalid cost for instruction: %7 = call <vscale x 2 x float> @llvm.minimum.nxv2f32(<vscale x 2 x float> undef, <vscale x 2 x float> undef)
 ; CHECK-NEXT:  Cost Model: Invalid cost for instruction: %8 = call <vscale x 4 x float> @llvm.minimum.nxv4f32(<vscale x 4 x float> undef, <vscale x 4 x float> undef)
 ; CHECK-NEXT:  Cost Model: Invalid cost for instruction: %9 = call <vscale x 8 x float> @llvm.minimum.nxv8f32(<vscale x 8 x float> undef, <vscale x 8 x float> undef)
 ; CHECK-NEXT:  Cost Model: Invalid cost for instruction: %10 = call <vscale x 16 x float> @llvm.minimum.nxv16f32(<vscale x 16 x float> undef, <vscale x 16 x float> undef)
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 10 for instruction: %11 = call double @llvm.minimum.f64(double undef, double undef)
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 23 for instruction: %12 = call <2 x double> @llvm.minimum.v2f64(<2 x double> undef, <2 x double> undef)
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 47 for instruction: %13 = call <4 x double> @llvm.minimum.v4f64(<4 x double> undef, <4 x double> undef)
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 95 for instruction: %14 = call <8 x double> @llvm.minimum.v8f64(<8 x double> undef, <8 x double> undef)
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 191 for instruction: %15 = call <16 x double> @llvm.minimum.v16f64(<16 x double> undef, <16 x double> undef)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 2 for instruction: %11 = call double @llvm.minimum.f64(double undef, double undef)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 7 for instruction: %12 = call <2 x double> @llvm.minimum.v2f64(<2 x double> undef, <2 x double> undef)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 15 for instruction: %13 = call <4 x double> @llvm.minimum.v4f64(<4 x double> undef, <4 x double> undef)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 31 for instruction: %14 = call <8 x double> @llvm.minimum.v8f64(<8 x double> undef, <8 x double> undef)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 63 for instruction: %15 = call <16 x double> @llvm.minimum.v16f64(<16 x double> undef, <16 x double> undef)
 ; CHECK-NEXT:  Cost Model: Invalid cost for instruction: %16 = call <vscale x 1 x double> @llvm.minimum.nxv1f64(<vscale x 1 x double> undef, <vscale x 1 x double> undef)
 ; CHECK-NEXT:  Cost Model: Invalid cost for instruction: %17 = call <vscale x 2 x double> @llvm.minimum.nxv2f64(<vscale x 2 x double> undef, <vscale x 2 x double> undef)
 ; CHECK-NEXT:  Cost Model: Invalid cost for instruction: %18 = call <vscale x 4 x double> @llvm.minimum.nxv4f64(<vscale x 4 x double> undef, <vscale x 4 x double> undef)
@@ -202,21 +202,21 @@ define void @minimum() {
 
 define void @maximum() {
 ; CHECK-LABEL: 'maximum'
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 10 for instruction: %1 = call float @llvm.maximum.f32(float undef, float undef)
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 23 for instruction: %2 = call <2 x float> @llvm.maximum.v2f32(<2 x float> undef, <2 x float> undef)
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 47 for instruction: %3 = call <4 x float> @llvm.maximum.v4f32(<4 x float> undef, <4 x float> undef)
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 95 for instruction: %4 = call <8 x float> @llvm.maximum.v8f32(<8 x float> undef, <8 x float> undef)
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 191 for instruction: %5 = call <16 x float> @llvm.maximum.v16f32(<16 x float> undef, <16 x float> undef)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 2 for instruction: %1 = call float @llvm.maximum.f32(float undef, float undef)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 7 for instruction: %2 = call <2 x float> @llvm.maximum.v2f32(<2 x float> undef, <2 x float> undef)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 15 for instruction: %3 = call <4 x float> @llvm.maximum.v4f32(<4 x float> undef, <4 x float> undef)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 31 for instruction: %4 = call <8 x float> @llvm.maximum.v8f32(<8 x float> undef, <8 x float> undef)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 63 for instruction: %5 = call <16 x float> @llvm.maximum.v16f32(<16 x float> undef, <16 x float> undef)
 ; CHECK-NEXT:  Cost Model: Invalid cost for instruction: %6 = call <vscale x 1 x float> @llvm.maximum.nxv1f32(<vscale x 1 x float> undef, <vscale x 1 x float> undef)
 ; CHECK-NEXT:  Cost Model: Invalid cost for instruction: %7 = call <vscale x 2 x float> @llvm.maximum.nxv2f32(<vscale x 2 x float> undef, <vscale x 2 x float> undef)
 ; CHECK-NEXT:  Cost Model: Invalid cost for instruction: %8 = call <vscale x 4 x float> @llvm.maximum.nxv4f32(<vscale x 4 x float> undef, <vscale x 4 x float> undef)
 ; CHECK-NEXT:  Cost Model: Invalid cost for instruction: %9 = call <vscale x 8 x float> @llvm.maximum.nxv8f32(<vscale x 8 x float> undef, <vscale x 8 x float> undef)
 ; CHECK-NEXT:  Cost Model: Invalid cost for instruction: %10 = call <vscale x 16 x float> @llvm.maximum.nxv16f32(<vscale x 16 x float> undef, <vscale x 16 x float> undef)
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 10 for instruction: %11 = call double @llvm.maximum.f64(double undef, double undef)
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 23 for instruction: %12 = call <2 x double> @llvm.maximum.v2f64(<2 x double> undef, <2 x double> undef)
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 47 for instruction: %13 = call <4 x double> @llvm.maximum.v4f64(<4 x double> undef, <4 x double> undef)
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 95 for instruction: %14 = call <8 x double> @llvm.maximum.v8f64(<8 x double> undef, <8 x double> undef)
-; CHECK-NEXT:  Cost Model: Found an estimated cost of 191 for instruction: %15 = call <16 x double> @llvm.maximum.v16f64(<16 x double> undef, <16 x double> undef)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 2 for instruction: %11 = call double @llvm.maximum.f64(double undef, double undef)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 7 for instruction: %12 = call <2 x double> @llvm.maximum.v2f64(<2 x double> undef, <2 x double> undef)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 15 for instruction: %13 = call <4 x double> @llvm.maximum.v4f64(<4 x double> undef, <4 x double> undef)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 31 for instruction: %14 = call <8 x double> @llvm.maximum.v8f64(<8 x double> undef, <8 x double> undef)
+; CHECK-NEXT:  Cost Model: Found an estimated cost of 63 for instruction: %15 = call <16 x double> @llvm.maximum.v16f64(<16 x double> undef, <16 x double> undef)
 ; CHECK-NEXT:  Cost Model: Invalid cost for instruction: %16 = call <vscale x 1 x double> @llvm.maximum.nxv1f64(<vscale x 1 x double> undef, <vscale x 1 x double> undef)
 ; CHECK-NEXT:  Cost Model: Invalid cost for instruction: %17 = call <vscale x 2 x double> @llvm.maximum.nxv2f64(<vscale x 2 x double> undef, <vscale x 2 x double> undef)
 ; CHECK-NEXT:  Cost Model: Invalid cost for instruction: %18 = call <vscale x 4 x double> @llvm.maximum.nxv4f64(<vscale x 4 x double> undef, <vscale x 4 x double> undef)

diff  --git a/llvm/test/CodeGen/RISCV/double-maximum-minimum.ll b/llvm/test/CodeGen/RISCV/double-maximum-minimum.ll
new file mode 100644
index 00000000000000..873f2c068f636f
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/double-maximum-minimum.ll
@@ -0,0 +1,164 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: sed 's/iXLen/i32/g' %s | llc -mtriple=riscv32 -mattr=+d \
+; RUN:   -verify-machineinstrs -target-abi=ilp32d \
+; RUN:   | FileCheck -check-prefixes=CHECKIFD,RV32IFD %s
+; RUN: sed 's/iXLen/i64/g' %s | llc -mtriple=riscv64 -mattr=+d \
+; RUN:   -verify-machineinstrs -target-abi=lp64d \
+; RUN:   | FileCheck -check-prefixes=CHECKIFD,RV64IFD %s
+; RUN: sed 's/iXLen/i32/g' %s | llc -mtriple=riscv32 -mattr=+zdinx \
+; RUN:   -verify-machineinstrs -target-abi=ilp32 \
+; RUN:   | FileCheck -check-prefix=RV32IZFINXZDINX %s
+; RUN: sed 's/iXLen/i64/g' %s | llc -mtriple=riscv64 -mattr=+zdinx \
+; RUN:   -verify-machineinstrs -target-abi=lp64 \
+; RUN:   | FileCheck -check-prefix=RV64IZFINXZDINX %s
+
+declare double @llvm.minimum.f64(double, double)
+
+define double @fminimum_f64(double %a, double %b) nounwind {
+; CHECKIFD-LABEL: fminimum_f64:
+; CHECKIFD:       # %bb.0:
+; CHECKIFD-NEXT:    feq.d a0, fa0, fa0
+; CHECKIFD-NEXT:    fmv.d fa5, fa1
+; CHECKIFD-NEXT:    beqz a0, .LBB0_3
+; CHECKIFD-NEXT:  # %bb.1:
+; CHECKIFD-NEXT:    feq.d a0, fa1, fa1
+; CHECKIFD-NEXT:    beqz a0, .LBB0_4
+; CHECKIFD-NEXT:  .LBB0_2:
+; CHECKIFD-NEXT:    fmin.d fa0, fa0, fa5
+; CHECKIFD-NEXT:    ret
+; CHECKIFD-NEXT:  .LBB0_3:
+; CHECKIFD-NEXT:    fmv.d fa5, fa0
+; CHECKIFD-NEXT:    feq.d a0, fa1, fa1
+; CHECKIFD-NEXT:    bnez a0, .LBB0_2
+; CHECKIFD-NEXT:  .LBB0_4:
+; CHECKIFD-NEXT:    fmin.d fa0, fa1, fa5
+; CHECKIFD-NEXT:    ret
+;
+; RV32IZFINXZDINX-LABEL: fminimum_f64:
+; RV32IZFINXZDINX:       # %bb.0:
+; RV32IZFINXZDINX-NEXT:    addi sp, sp, -16
+; RV32IZFINXZDINX-NEXT:    sw a2, 8(sp)
+; RV32IZFINXZDINX-NEXT:    sw a3, 12(sp)
+; RV32IZFINXZDINX-NEXT:    lw a2, 8(sp)
+; RV32IZFINXZDINX-NEXT:    lw a3, 12(sp)
+; RV32IZFINXZDINX-NEXT:    sw a0, 8(sp)
+; RV32IZFINXZDINX-NEXT:    sw a1, 12(sp)
+; RV32IZFINXZDINX-NEXT:    lw a0, 8(sp)
+; RV32IZFINXZDINX-NEXT:    lw a1, 12(sp)
+; RV32IZFINXZDINX-NEXT:    feq.d a6, a0, a0
+; RV32IZFINXZDINX-NEXT:    mv a4, a2
+; RV32IZFINXZDINX-NEXT:    bnez a6, .LBB0_2
+; RV32IZFINXZDINX-NEXT:  # %bb.1:
+; RV32IZFINXZDINX-NEXT:    mv a4, a0
+; RV32IZFINXZDINX-NEXT:  .LBB0_2:
+; RV32IZFINXZDINX-NEXT:    feq.d a6, a2, a2
+; RV32IZFINXZDINX-NEXT:    bnez a6, .LBB0_4
+; RV32IZFINXZDINX-NEXT:  # %bb.3:
+; RV32IZFINXZDINX-NEXT:    mv a0, a2
+; RV32IZFINXZDINX-NEXT:  .LBB0_4:
+; RV32IZFINXZDINX-NEXT:    fmin.d a0, a0, a4
+; RV32IZFINXZDINX-NEXT:    sw a0, 8(sp)
+; RV32IZFINXZDINX-NEXT:    sw a1, 12(sp)
+; RV32IZFINXZDINX-NEXT:    lw a0, 8(sp)
+; RV32IZFINXZDINX-NEXT:    lw a1, 12(sp)
+; RV32IZFINXZDINX-NEXT:    addi sp, sp, 16
+; RV32IZFINXZDINX-NEXT:    ret
+;
+; RV64IZFINXZDINX-LABEL: fminimum_f64:
+; RV64IZFINXZDINX:       # %bb.0:
+; RV64IZFINXZDINX-NEXT:    feq.d a3, a0, a0
+; RV64IZFINXZDINX-NEXT:    mv a2, a1
+; RV64IZFINXZDINX-NEXT:    beqz a3, .LBB0_3
+; RV64IZFINXZDINX-NEXT:  # %bb.1:
+; RV64IZFINXZDINX-NEXT:    feq.d a3, a1, a1
+; RV64IZFINXZDINX-NEXT:    beqz a3, .LBB0_4
+; RV64IZFINXZDINX-NEXT:  .LBB0_2:
+; RV64IZFINXZDINX-NEXT:    fmin.d a0, a0, a2
+; RV64IZFINXZDINX-NEXT:    ret
+; RV64IZFINXZDINX-NEXT:  .LBB0_3:
+; RV64IZFINXZDINX-NEXT:    mv a2, a0
+; RV64IZFINXZDINX-NEXT:    feq.d a3, a1, a1
+; RV64IZFINXZDINX-NEXT:    bnez a3, .LBB0_2
+; RV64IZFINXZDINX-NEXT:  .LBB0_4:
+; RV64IZFINXZDINX-NEXT:    fmin.d a0, a1, a2
+; RV64IZFINXZDINX-NEXT:    ret
+  %1 = call double @llvm.minimum.f64(double %a, double %b)
+  ret double %1
+}
+
+declare double @llvm.maximum.f64(double, double)
+
+define double @fmaximum_f64(double %a, double %b) nounwind {
+; CHECKIFD-LABEL: fmaximum_f64:
+; CHECKIFD:       # %bb.0:
+; CHECKIFD-NEXT:    feq.d a0, fa0, fa0
+; CHECKIFD-NEXT:    fmv.d fa5, fa1
+; CHECKIFD-NEXT:    beqz a0, .LBB1_3
+; CHECKIFD-NEXT:  # %bb.1:
+; CHECKIFD-NEXT:    feq.d a0, fa1, fa1
+; CHECKIFD-NEXT:    beqz a0, .LBB1_4
+; CHECKIFD-NEXT:  .LBB1_2:
+; CHECKIFD-NEXT:    fmax.d fa0, fa0, fa5
+; CHECKIFD-NEXT:    ret
+; CHECKIFD-NEXT:  .LBB1_3:
+; CHECKIFD-NEXT:    fmv.d fa5, fa0
+; CHECKIFD-NEXT:    feq.d a0, fa1, fa1
+; CHECKIFD-NEXT:    bnez a0, .LBB1_2
+; CHECKIFD-NEXT:  .LBB1_4:
+; CHECKIFD-NEXT:    fmax.d fa0, fa1, fa5
+; CHECKIFD-NEXT:    ret
+;
+; RV32IZFINXZDINX-LABEL: fmaximum_f64:
+; RV32IZFINXZDINX:       # %bb.0:
+; RV32IZFINXZDINX-NEXT:    addi sp, sp, -16
+; RV32IZFINXZDINX-NEXT:    sw a2, 8(sp)
+; RV32IZFINXZDINX-NEXT:    sw a3, 12(sp)
+; RV32IZFINXZDINX-NEXT:    lw a2, 8(sp)
+; RV32IZFINXZDINX-NEXT:    lw a3, 12(sp)
+; RV32IZFINXZDINX-NEXT:    sw a0, 8(sp)
+; RV32IZFINXZDINX-NEXT:    sw a1, 12(sp)
+; RV32IZFINXZDINX-NEXT:    lw a0, 8(sp)
+; RV32IZFINXZDINX-NEXT:    lw a1, 12(sp)
+; RV32IZFINXZDINX-NEXT:    feq.d a6, a0, a0
+; RV32IZFINXZDINX-NEXT:    mv a4, a2
+; RV32IZFINXZDINX-NEXT:    bnez a6, .LBB1_2
+; RV32IZFINXZDINX-NEXT:  # %bb.1:
+; RV32IZFINXZDINX-NEXT:    mv a4, a0
+; RV32IZFINXZDINX-NEXT:  .LBB1_2:
+; RV32IZFINXZDINX-NEXT:    feq.d a6, a2, a2
+; RV32IZFINXZDINX-NEXT:    bnez a6, .LBB1_4
+; RV32IZFINXZDINX-NEXT:  # %bb.3:
+; RV32IZFINXZDINX-NEXT:    mv a0, a2
+; RV32IZFINXZDINX-NEXT:  .LBB1_4:
+; RV32IZFINXZDINX-NEXT:    fmax.d a0, a0, a4
+; RV32IZFINXZDINX-NEXT:    sw a0, 8(sp)
+; RV32IZFINXZDINX-NEXT:    sw a1, 12(sp)
+; RV32IZFINXZDINX-NEXT:    lw a0, 8(sp)
+; RV32IZFINXZDINX-NEXT:    lw a1, 12(sp)
+; RV32IZFINXZDINX-NEXT:    addi sp, sp, 16
+; RV32IZFINXZDINX-NEXT:    ret
+;
+; RV64IZFINXZDINX-LABEL: fmaximum_f64:
+; RV64IZFINXZDINX:       # %bb.0:
+; RV64IZFINXZDINX-NEXT:    feq.d a3, a0, a0
+; RV64IZFINXZDINX-NEXT:    mv a2, a1
+; RV64IZFINXZDINX-NEXT:    beqz a3, .LBB1_3
+; RV64IZFINXZDINX-NEXT:  # %bb.1:
+; RV64IZFINXZDINX-NEXT:    feq.d a3, a1, a1
+; RV64IZFINXZDINX-NEXT:    beqz a3, .LBB1_4
+; RV64IZFINXZDINX-NEXT:  .LBB1_2:
+; RV64IZFINXZDINX-NEXT:    fmax.d a0, a0, a2
+; RV64IZFINXZDINX-NEXT:    ret
+; RV64IZFINXZDINX-NEXT:  .LBB1_3:
+; RV64IZFINXZDINX-NEXT:    mv a2, a0
+; RV64IZFINXZDINX-NEXT:    feq.d a3, a1, a1
+; RV64IZFINXZDINX-NEXT:    bnez a3, .LBB1_2
+; RV64IZFINXZDINX-NEXT:  .LBB1_4:
+; RV64IZFINXZDINX-NEXT:    fmax.d a0, a1, a2
+; RV64IZFINXZDINX-NEXT:    ret
+  %1 = call double @llvm.maximum.f64(double %a, double %b)
+  ret double %1
+}
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; RV32IFD: {{.*}}
+; RV64IFD: {{.*}}

diff  --git a/llvm/test/CodeGen/RISCV/float-maximum-minimum.ll b/llvm/test/CodeGen/RISCV/float-maximum-minimum.ll
new file mode 100644
index 00000000000000..48a58ea111585a
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/float-maximum-minimum.ll
@@ -0,0 +1,183 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: sed 's/iXLen/i32/g' %s | llc -mtriple=riscv32 -mattr=+f \
+; RUN:   -verify-machineinstrs -target-abi=ilp32f \
+; RUN:   | FileCheck -check-prefix=RV32IF %s
+; RUN: sed 's/iXLen/i32/g' %s | llc -mtriple=riscv32 -mattr=+zfinx \
+; RUN:   -verify-machineinstrs -target-abi=ilp32 \
+; RUN:   | FileCheck -check-prefix=RV32IZFINX %s
+; RUN: sed 's/iXLen/i32/g' %s | llc -mtriple=riscv32 -mattr=+d \
+; RUN:   -verify-machineinstrs -target-abi=ilp32f \
+; RUN:   | FileCheck -check-prefix=RV32IF %s
+; RUN: sed 's/iXLen/i64/g' %s | llc -mtriple=riscv64 -mattr=+f \
+; RUN:   -verify-machineinstrs -target-abi=lp64f \
+; RUN:   | FileCheck -check-prefix=RV64IF %s
+; RUN: sed 's/iXLen/i64/g' %s | llc -mtriple=riscv64 -mattr=+zfinx \
+; RUN:   -verify-machineinstrs -target-abi=lp64 \
+; RUN:   | FileCheck -check-prefix=RV64IZFINX %s
+; RUN: sed 's/iXLen/i64/g' %s | llc -mtriple=riscv64 -mattr=+d \
+; RUN:   -verify-machineinstrs -target-abi=lp64d \
+; RUN:   | FileCheck -check-prefix=RV64IF %s
+
+declare float @llvm.minimum.f32(float, float)
+
+define float @fminimum_f32(float %a, float %b) nounwind {
+; RV32IF-LABEL: fminimum_f32:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    feq.s a0, fa0, fa0
+; RV32IF-NEXT:    fmv.s fa5, fa1
+; RV32IF-NEXT:    beqz a0, .LBB0_3
+; RV32IF-NEXT:  # %bb.1:
+; RV32IF-NEXT:    feq.s a0, fa1, fa1
+; RV32IF-NEXT:    beqz a0, .LBB0_4
+; RV32IF-NEXT:  .LBB0_2:
+; RV32IF-NEXT:    fmin.s fa0, fa0, fa5
+; RV32IF-NEXT:    ret
+; RV32IF-NEXT:  .LBB0_3:
+; RV32IF-NEXT:    fmv.s fa5, fa0
+; RV32IF-NEXT:    feq.s a0, fa1, fa1
+; RV32IF-NEXT:    bnez a0, .LBB0_2
+; RV32IF-NEXT:  .LBB0_4:
+; RV32IF-NEXT:    fmin.s fa0, fa1, fa5
+; RV32IF-NEXT:    ret
+;
+; RV32IZFINX-LABEL: fminimum_f32:
+; RV32IZFINX:       # %bb.0:
+; RV32IZFINX-NEXT:    feq.s a3, a0, a0
+; RV32IZFINX-NEXT:    mv a2, a1
+; RV32IZFINX-NEXT:    beqz a3, .LBB0_3
+; RV32IZFINX-NEXT:  # %bb.1:
+; RV32IZFINX-NEXT:    feq.s a3, a1, a1
+; RV32IZFINX-NEXT:    beqz a3, .LBB0_4
+; RV32IZFINX-NEXT:  .LBB0_2:
+; RV32IZFINX-NEXT:    fmin.s a0, a0, a2
+; RV32IZFINX-NEXT:    ret
+; RV32IZFINX-NEXT:  .LBB0_3:
+; RV32IZFINX-NEXT:    mv a2, a0
+; RV32IZFINX-NEXT:    feq.s a3, a1, a1
+; RV32IZFINX-NEXT:    bnez a3, .LBB0_2
+; RV32IZFINX-NEXT:  .LBB0_4:
+; RV32IZFINX-NEXT:    fmin.s a0, a1, a2
+; RV32IZFINX-NEXT:    ret
+;
+; RV64IF-LABEL: fminimum_f32:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    feq.s a0, fa0, fa0
+; RV64IF-NEXT:    fmv.s fa5, fa1
+; RV64IF-NEXT:    beqz a0, .LBB0_3
+; RV64IF-NEXT:  # %bb.1:
+; RV64IF-NEXT:    feq.s a0, fa1, fa1
+; RV64IF-NEXT:    beqz a0, .LBB0_4
+; RV64IF-NEXT:  .LBB0_2:
+; RV64IF-NEXT:    fmin.s fa0, fa0, fa5
+; RV64IF-NEXT:    ret
+; RV64IF-NEXT:  .LBB0_3:
+; RV64IF-NEXT:    fmv.s fa5, fa0
+; RV64IF-NEXT:    feq.s a0, fa1, fa1
+; RV64IF-NEXT:    bnez a0, .LBB0_2
+; RV64IF-NEXT:  .LBB0_4:
+; RV64IF-NEXT:    fmin.s fa0, fa1, fa5
+; RV64IF-NEXT:    ret
+;
+; RV64IZFINX-LABEL: fminimum_f32:
+; RV64IZFINX:       # %bb.0:
+; RV64IZFINX-NEXT:    feq.s a3, a0, a0
+; RV64IZFINX-NEXT:    mv a2, a1
+; RV64IZFINX-NEXT:    beqz a3, .LBB0_3
+; RV64IZFINX-NEXT:  # %bb.1:
+; RV64IZFINX-NEXT:    feq.s a3, a1, a1
+; RV64IZFINX-NEXT:    beqz a3, .LBB0_4
+; RV64IZFINX-NEXT:  .LBB0_2:
+; RV64IZFINX-NEXT:    fmin.s a0, a0, a2
+; RV64IZFINX-NEXT:    ret
+; RV64IZFINX-NEXT:  .LBB0_3:
+; RV64IZFINX-NEXT:    mv a2, a0
+; RV64IZFINX-NEXT:    feq.s a3, a1, a1
+; RV64IZFINX-NEXT:    bnez a3, .LBB0_2
+; RV64IZFINX-NEXT:  .LBB0_4:
+; RV64IZFINX-NEXT:    fmin.s a0, a1, a2
+; RV64IZFINX-NEXT:    ret
+  %1 = call float @llvm.minimum.f32(float %a, float %b)
+  ret float %1
+}
+
+declare float @llvm.maximum.f32(float, float)
+
+define float @fmaximum_f32(float %a, float %b) nounwind {
+; RV32IF-LABEL: fmaximum_f32:
+; RV32IF:       # %bb.0:
+; RV32IF-NEXT:    feq.s a0, fa0, fa0
+; RV32IF-NEXT:    fmv.s fa5, fa1
+; RV32IF-NEXT:    beqz a0, .LBB1_3
+; RV32IF-NEXT:  # %bb.1:
+; RV32IF-NEXT:    feq.s a0, fa1, fa1
+; RV32IF-NEXT:    beqz a0, .LBB1_4
+; RV32IF-NEXT:  .LBB1_2:
+; RV32IF-NEXT:    fmax.s fa0, fa0, fa5
+; RV32IF-NEXT:    ret
+; RV32IF-NEXT:  .LBB1_3:
+; RV32IF-NEXT:    fmv.s fa5, fa0
+; RV32IF-NEXT:    feq.s a0, fa1, fa1
+; RV32IF-NEXT:    bnez a0, .LBB1_2
+; RV32IF-NEXT:  .LBB1_4:
+; RV32IF-NEXT:    fmax.s fa0, fa1, fa5
+; RV32IF-NEXT:    ret
+;
+; RV32IZFINX-LABEL: fmaximum_f32:
+; RV32IZFINX:       # %bb.0:
+; RV32IZFINX-NEXT:    feq.s a3, a0, a0
+; RV32IZFINX-NEXT:    mv a2, a1
+; RV32IZFINX-NEXT:    beqz a3, .LBB1_3
+; RV32IZFINX-NEXT:  # %bb.1:
+; RV32IZFINX-NEXT:    feq.s a3, a1, a1
+; RV32IZFINX-NEXT:    beqz a3, .LBB1_4
+; RV32IZFINX-NEXT:  .LBB1_2:
+; RV32IZFINX-NEXT:    fmax.s a0, a0, a2
+; RV32IZFINX-NEXT:    ret
+; RV32IZFINX-NEXT:  .LBB1_3:
+; RV32IZFINX-NEXT:    mv a2, a0
+; RV32IZFINX-NEXT:    feq.s a3, a1, a1
+; RV32IZFINX-NEXT:    bnez a3, .LBB1_2
+; RV32IZFINX-NEXT:  .LBB1_4:
+; RV32IZFINX-NEXT:    fmax.s a0, a1, a2
+; RV32IZFINX-NEXT:    ret
+;
+; RV64IF-LABEL: fmaximum_f32:
+; RV64IF:       # %bb.0:
+; RV64IF-NEXT:    feq.s a0, fa0, fa0
+; RV64IF-NEXT:    fmv.s fa5, fa1
+; RV64IF-NEXT:    beqz a0, .LBB1_3
+; RV64IF-NEXT:  # %bb.1:
+; RV64IF-NEXT:    feq.s a0, fa1, fa1
+; RV64IF-NEXT:    beqz a0, .LBB1_4
+; RV64IF-NEXT:  .LBB1_2:
+; RV64IF-NEXT:    fmax.s fa0, fa0, fa5
+; RV64IF-NEXT:    ret
+; RV64IF-NEXT:  .LBB1_3:
+; RV64IF-NEXT:    fmv.s fa5, fa0
+; RV64IF-NEXT:    feq.s a0, fa1, fa1
+; RV64IF-NEXT:    bnez a0, .LBB1_2
+; RV64IF-NEXT:  .LBB1_4:
+; RV64IF-NEXT:    fmax.s fa0, fa1, fa5
+; RV64IF-NEXT:    ret
+;
+; RV64IZFINX-LABEL: fmaximum_f32:
+; RV64IZFINX:       # %bb.0:
+; RV64IZFINX-NEXT:    feq.s a3, a0, a0
+; RV64IZFINX-NEXT:    mv a2, a1
+; RV64IZFINX-NEXT:    beqz a3, .LBB1_3
+; RV64IZFINX-NEXT:  # %bb.1:
+; RV64IZFINX-NEXT:    feq.s a3, a1, a1
+; RV64IZFINX-NEXT:    beqz a3, .LBB1_4
+; RV64IZFINX-NEXT:  .LBB1_2:
+; RV64IZFINX-NEXT:    fmax.s a0, a0, a2
+; RV64IZFINX-NEXT:    ret
+; RV64IZFINX-NEXT:  .LBB1_3:
+; RV64IZFINX-NEXT:    mv a2, a0
+; RV64IZFINX-NEXT:    feq.s a3, a1, a1
+; RV64IZFINX-NEXT:    bnez a3, .LBB1_2
+; RV64IZFINX-NEXT:  .LBB1_4:
+; RV64IZFINX-NEXT:    fmax.s a0, a1, a2
+; RV64IZFINX-NEXT:    ret
+  %1 = call float @llvm.maximum.f32(float %a, float %b)
+  ret float %1
+}

diff  --git a/llvm/test/CodeGen/RISCV/half-maximum-minimum.ll b/llvm/test/CodeGen/RISCV/half-maximum-minimum.ll
new file mode 100644
index 00000000000000..267a2083c80f6a
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/half-maximum-minimum.ll
@@ -0,0 +1,101 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: sed 's/iXLen/i32/g' %s | llc -mtriple=riscv32 -mattr=+zfh \
+; RUN:   -verify-machineinstrs -target-abi ilp32f | \
+; RUN:   FileCheck -check-prefixes=CHECKIZFH %s
+; RUN: sed 's/iXLen/i64/g' %s | llc -mtriple=riscv64 -mattr=+zfh \
+; RUN:   -verify-machineinstrs -target-abi lp64f | \
+; RUN:   FileCheck -check-prefixes=CHECKIZFH %s
+; RUN: sed 's/iXLen/i32/g' %s | llc -mtriple=riscv32 -mattr=+zhinx \
+; RUN:   -verify-machineinstrs -target-abi ilp32 | \
+; RUN:   FileCheck -check-prefixes=CHECKIZHINX %s
+; RUN: sed 's/iXLen/i64/g' %s | llc -mtriple=riscv64 -mattr=+zhinx \
+; RUN:   -verify-machineinstrs -target-abi lp64 | \
+; RUN:   FileCheck -check-prefixes=CHECKIZHINX %s
+
+declare half @llvm.minimum.f16(half, half)
+
+define half @fminimum_f16(half %a, half %b) nounwind {
+; CHECKIZFH-LABEL: fminimum_f16:
+; CHECKIZFH:       # %bb.0:
+; CHECKIZFH-NEXT:    feq.h a0, fa0, fa0
+; CHECKIZFH-NEXT:    fmv.h fa5, fa1
+; CHECKIZFH-NEXT:    beqz a0, .LBB0_3
+; CHECKIZFH-NEXT:  # %bb.1:
+; CHECKIZFH-NEXT:    feq.h a0, fa1, fa1
+; CHECKIZFH-NEXT:    beqz a0, .LBB0_4
+; CHECKIZFH-NEXT:  .LBB0_2:
+; CHECKIZFH-NEXT:    fmin.h fa0, fa0, fa5
+; CHECKIZFH-NEXT:    ret
+; CHECKIZFH-NEXT:  .LBB0_3:
+; CHECKIZFH-NEXT:    fmv.h fa5, fa0
+; CHECKIZFH-NEXT:    feq.h a0, fa1, fa1
+; CHECKIZFH-NEXT:    bnez a0, .LBB0_2
+; CHECKIZFH-NEXT:  .LBB0_4:
+; CHECKIZFH-NEXT:    fmin.h fa0, fa1, fa5
+; CHECKIZFH-NEXT:    ret
+;
+; CHECKIZHINX-LABEL: fminimum_f16:
+; CHECKIZHINX:       # %bb.0:
+; CHECKIZHINX-NEXT:    feq.h a3, a0, a0
+; CHECKIZHINX-NEXT:    mv a2, a1
+; CHECKIZHINX-NEXT:    beqz a3, .LBB0_3
+; CHECKIZHINX-NEXT:  # %bb.1:
+; CHECKIZHINX-NEXT:    feq.h a3, a1, a1
+; CHECKIZHINX-NEXT:    beqz a3, .LBB0_4
+; CHECKIZHINX-NEXT:  .LBB0_2:
+; CHECKIZHINX-NEXT:    fmin.h a0, a0, a2
+; CHECKIZHINX-NEXT:    ret
+; CHECKIZHINX-NEXT:  .LBB0_3:
+; CHECKIZHINX-NEXT:    mv a2, a0
+; CHECKIZHINX-NEXT:    feq.h a3, a1, a1
+; CHECKIZHINX-NEXT:    bnez a3, .LBB0_2
+; CHECKIZHINX-NEXT:  .LBB0_4:
+; CHECKIZHINX-NEXT:    fmin.h a0, a1, a2
+; CHECKIZHINX-NEXT:    ret
+  %1 = call half @llvm.minimum.f16(half %a, half %b)
+  ret half %1
+}
+
+declare half @llvm.maximum.f16(half, half)
+
+define half @fmaximum_f16(half %a, half %b) nounwind {
+; CHECKIZFH-LABEL: fmaximum_f16:
+; CHECKIZFH:       # %bb.0:
+; CHECKIZFH-NEXT:    feq.h a0, fa0, fa0
+; CHECKIZFH-NEXT:    fmv.h fa5, fa1
+; CHECKIZFH-NEXT:    beqz a0, .LBB1_3
+; CHECKIZFH-NEXT:  # %bb.1:
+; CHECKIZFH-NEXT:    feq.h a0, fa1, fa1
+; CHECKIZFH-NEXT:    beqz a0, .LBB1_4
+; CHECKIZFH-NEXT:  .LBB1_2:
+; CHECKIZFH-NEXT:    fmax.h fa0, fa0, fa5
+; CHECKIZFH-NEXT:    ret
+; CHECKIZFH-NEXT:  .LBB1_3:
+; CHECKIZFH-NEXT:    fmv.h fa5, fa0
+; CHECKIZFH-NEXT:    feq.h a0, fa1, fa1
+; CHECKIZFH-NEXT:    bnez a0, .LBB1_2
+; CHECKIZFH-NEXT:  .LBB1_4:
+; CHECKIZFH-NEXT:    fmax.h fa0, fa1, fa5
+; CHECKIZFH-NEXT:    ret
+;
+; CHECKIZHINX-LABEL: fmaximum_f16:
+; CHECKIZHINX:       # %bb.0:
+; CHECKIZHINX-NEXT:    feq.h a3, a0, a0
+; CHECKIZHINX-NEXT:    mv a2, a1
+; CHECKIZHINX-NEXT:    beqz a3, .LBB1_3
+; CHECKIZHINX-NEXT:  # %bb.1:
+; CHECKIZHINX-NEXT:    feq.h a3, a1, a1
+; CHECKIZHINX-NEXT:    beqz a3, .LBB1_4
+; CHECKIZHINX-NEXT:  .LBB1_2:
+; CHECKIZHINX-NEXT:    fmax.h a0, a0, a2
+; CHECKIZHINX-NEXT:    ret
+; CHECKIZHINX-NEXT:  .LBB1_3:
+; CHECKIZHINX-NEXT:    mv a2, a0
+; CHECKIZHINX-NEXT:    feq.h a3, a1, a1
+; CHECKIZHINX-NEXT:    bnez a3, .LBB1_2
+; CHECKIZHINX-NEXT:  .LBB1_4:
+; CHECKIZHINX-NEXT:    fmax.h a0, a1, a2
+; CHECKIZHINX-NEXT:    ret
+  %1 = call half @llvm.maximum.f16(half %a, half %b)
+  ret half %1
+}


        


More information about the llvm-commits mailing list