[llvm] [SPIR-V] Lower llvm.minimum/maximum instead of selecting fmin/fmax (PR #225667)

Tim Besard via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 23 03:14:18 PDT 2026


https://github.com/maleadt created https://github.com/llvm/llvm-project/pull/225667

Fixes #225665. The SPIRV-LLVM-Translator equivalent is KhronosGroup/SPIRV-LLVM-Translator#4032.

`G_FMINIMUM`/`G_FMAXIMUM` were legal and selected to `fmin`/`fmax` (`NMin`/`NMax`), which neither propagate NaNs nor order signed zeros. This marks them `lower` so that they use the generic `LegalizerHelper::lowerFMinimumMaximum`. That expansion computes `fmin`/`fmax`, selects a NaN if the operands are unordered (skipped under `nnan`), and fixes up signed zeros with `G_IS_FPCLASS` (skipped under `nsz`). A `nnan nsz` call therefore still compiles to a single `fmin`/`fmax`.

```
%min = OpExtInst %float %ext fmin %a %b
%ord = OpOrdered %bool %a %b
%sel = OpSelect %float %ord %min %nan
...                                   ; if %sel is zero, pick whichever operand is -0.0
```

Making the expansion selectable needed three more changes:

- `fcmp ord`/`uno` in shaders. The expansion relies on `fcmp ord`, but in shaders these were selected to `OpOrdered`/`OpUnordered`. Those require the `Kernel` capability, so any `fcmp ord`/`uno` in a Vulkan module was already invalid. In shaders they are now selected via `OpIsNan`. This is also a standalone fix, with its own test.
- `SPIRVPostLegalizer` now types `G_FCONSTANT` results from their immediate, `G_SELECT` results from the value operands instead of the condition, and untyped `COPY` results from their source. Previously these fell back to integer types or were left untyped.
- The `G_IS_FPCLASS` custom lowering now types an untyped source before bitcasting it. This happens with widened vectors.

In shaders, the signed-zero check makes `half`/`double` need `Int16`/`Int64`, the same as `llvm.is.fpclass` already does. `nsz` avoids this.

This supersedes the draft #180797, which took the same approach but didn't handle the untyped `G_IS_FPCLASS` source (its CI fails on it) or shaders, and had no tests. `minimumnum`/`maximumnum` are handled separately in #218641.

>From b6d6386a7e77e4763fdc796139b0f691bf6e6a2b Mon Sep 17 00:00:00 2001
From: Tim Besard <tim.besard at gmail.com>
Date: Wed, 23 Sep 2026 11:51:03 +0200
Subject: [PATCH 1/2] [SPIR-V] Don't emit OpOrdered/OpUnordered in shaders

OpOrdered and OpUnordered require the Kernel capability, so `fcmp ord`
and `fcmp uno` currently produce invalid SPIR-V for Vulkan targets:

  error: Opcode Ordered requires one of these capabilities: Kernel

For shaders, select them as OpIsNan on both operands combined with
OpLogicalOr, followed by OpLogicalNot for `ord`. None of these need an
additional capability.
---
 .../Target/SPIRV/SPIRVInstructionSelector.cpp | 36 +++++++++-
 .../SPIRV/instructions/fcmp-ord-uno-shader.ll | 68 +++++++++++++++++++
 2 files changed, 103 insertions(+), 1 deletion(-)
 create mode 100644 llvm/test/CodeGen/SPIRV/instructions/fcmp-ord-uno-shader.ll

diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index 0ea9e552ce2e3a..45cf5d9ab8635e 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -4583,7 +4583,41 @@ Register SPIRVInstructionSelector::buildI32ConstantInEntryBlock(
 bool SPIRVInstructionSelector::selectFCmp(Register ResVReg,
                                           SPIRVTypeInst ResType,
                                           MachineInstr &I) const {
-  unsigned CmpOp = getFCmpOpcode(I.getOperand(1).getPredicate());
+  auto Pred = I.getOperand(1).getPredicate();
+  // OpOrdered and OpUnordered require the Kernel capability. For shaders,
+  // express them as uno(a, b) = isnan(a) || isnan(b), ord(a, b) = !uno(a, b).
+  if (STI.isShader() &&
+      (Pred == CmpInst::FCMP_ORD || Pred == CmpInst::FCMP_UNO)) {
+    MachineBasicBlock &BB = *I.getParent();
+    Register ResTypeID = GR.getSPIRVTypeID(ResType);
+    Register IsNan[2];
+    for (unsigned Idx = 0; Idx < 2; ++Idx) {
+      IsNan[Idx] = createVirtualRegister(ResType, &GR, MRI, *I.getMF());
+      BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpIsNan))
+          .addDef(IsNan[Idx])
+          .addUse(ResTypeID)
+          .addUse(I.getOperand(2 + Idx).getReg())
+          .constrainAllUses(TII, TRI, RBI);
+    }
+    Register UnoReg =
+        Pred == CmpInst::FCMP_UNO
+            ? ResVReg
+            : createVirtualRegister(ResType, &GR, MRI, *I.getMF());
+    BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpLogicalOr))
+        .addDef(UnoReg)
+        .addUse(ResTypeID)
+        .addUse(IsNan[0])
+        .addUse(IsNan[1])
+        .constrainAllUses(TII, TRI, RBI);
+    if (Pred == CmpInst::FCMP_ORD)
+      BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpLogicalNot))
+          .addDef(ResVReg)
+          .addUse(ResTypeID)
+          .addUse(UnoReg)
+          .constrainAllUses(TII, TRI, RBI);
+    return true;
+  }
+  unsigned CmpOp = getFCmpOpcode(Pred);
   return selectCmp(ResVReg, ResType, CmpOp, I);
 }
 
diff --git a/llvm/test/CodeGen/SPIRV/instructions/fcmp-ord-uno-shader.ll b/llvm/test/CodeGen/SPIRV/instructions/fcmp-ord-uno-shader.ll
new file mode 100644
index 00000000000000..e57d1518e0ce9e
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/instructions/fcmp-ord-uno-shader.ll
@@ -0,0 +1,68 @@
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-vulkan %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan %s -o - -filetype=obj | spirv-val %}
+
+; OpOrdered and OpUnordered require the Kernel capability, so shaders use
+; OpIsNan instead.
+
+; CHECK-DAG: OpName [[ORD:%.*]] "test_ord"
+; CHECK-DAG: OpName [[UNO:%.*]] "test_uno"
+; CHECK-DAG: OpName [[v4ORD:%.*]] "test_v4_ord"
+; CHECK-DAG: OpName [[v4UNO:%.*]] "test_v4_uno"
+
+; CHECK:      [[ORD]] = OpFunction
+; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter
+; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter
+; CHECK-NEXT: OpLabel
+; CHECK-NEXT: [[NANA:%.*]] = OpIsNan [[BOOL:%.+]] [[A]]
+; CHECK-NEXT: [[NANB:%.*]] = OpIsNan [[BOOL]] [[B]]
+; CHECK-NEXT: [[UNOR:%.*]] = OpLogicalOr [[BOOL]] [[NANA]] [[NANB]]
+; CHECK-NEXT: [[R:%.*]] = OpLogicalNot [[BOOL]] [[UNOR]]
+; CHECK-NEXT: OpReturnValue [[R]]
+; CHECK-NEXT: OpFunctionEnd
+define i1 @test_ord(float %a, float %b) {
+  %r = fcmp ord float %a, %b
+  ret i1 %r
+}
+
+; CHECK:      [[UNO]] = OpFunction
+; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter
+; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter
+; CHECK-NEXT: OpLabel
+; CHECK-NEXT: [[NANA:%.*]] = OpIsNan [[BOOL]] [[A]]
+; CHECK-NEXT: [[NANB:%.*]] = OpIsNan [[BOOL]] [[B]]
+; CHECK-NEXT: [[R:%.*]] = OpLogicalOr [[BOOL]] [[NANA]] [[NANB]]
+; CHECK-NEXT: OpReturnValue [[R]]
+; CHECK-NEXT: OpFunctionEnd
+define i1 @test_uno(float %a, float %b) {
+  %r = fcmp uno float %a, %b
+  ret i1 %r
+}
+
+; CHECK:      [[v4ORD]] = OpFunction
+; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter
+; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter
+; CHECK-NEXT: OpLabel
+; CHECK-NEXT: [[NANA:%.*]] = OpIsNan [[V4BOOL:%.+]] [[A]]
+; CHECK-NEXT: [[NANB:%.*]] = OpIsNan [[V4BOOL]] [[B]]
+; CHECK-NEXT: [[UNOR:%.*]] = OpLogicalOr [[V4BOOL]] [[NANA]] [[NANB]]
+; CHECK-NEXT: [[R:%.*]] = OpLogicalNot [[V4BOOL]] [[UNOR]]
+; CHECK-NEXT: OpReturnValue [[R]]
+; CHECK-NEXT: OpFunctionEnd
+define <4 x i1> @test_v4_ord(<4 x float> %a, <4 x float> %b) {
+  %r = fcmp ord <4 x float> %a, %b
+  ret <4 x i1> %r
+}
+
+; CHECK:      [[v4UNO]] = OpFunction
+; CHECK-NEXT: [[A:%.*]] = OpFunctionParameter
+; CHECK-NEXT: [[B:%.*]] = OpFunctionParameter
+; CHECK-NEXT: OpLabel
+; CHECK-NEXT: [[NANA:%.*]] = OpIsNan [[V4BOOL]] [[A]]
+; CHECK-NEXT: [[NANB:%.*]] = OpIsNan [[V4BOOL]] [[B]]
+; CHECK-NEXT: [[R:%.*]] = OpLogicalOr [[V4BOOL]] [[NANA]] [[NANB]]
+; CHECK-NEXT: OpReturnValue [[R]]
+; CHECK-NEXT: OpFunctionEnd
+define <4 x i1> @test_v4_uno(<4 x float> %a, <4 x float> %b) {
+  %r = fcmp uno <4 x float> %a, %b
+  ret <4 x i1> %r
+}

>From f13ff6ad68b1d43f0da20c1b6bfa8908dbbf4891 Mon Sep 17 00:00:00 2001
From: Tim Besard <tim.besard at gmail.com>
Date: Wed, 23 Sep 2026 11:51:15 +0200
Subject: [PATCH 2/2] [SPIR-V] Lower llvm.minimum/maximum instead of selecting
 fmin/fmax

llvm.minimum and llvm.maximum follow IEEE 754-2019 minimum/maximum: if
either operand is NaN the result is NaN, and -0.0 is less than +0.0.
The SPIR-V back-end treated G_FMINIMUM/G_FMAXIMUM as legal and selected
them to OpenCL.std fmin/fmax (GLSL.std.450 NMin/NMax), exactly like
G_FMINNUM/G_FMAXNUM. Those implement IEEE 754-2008 minNum/maxNum, which
return the non-NaN operand and may return either zero, so e.g.
llvm.minimum(NaN, 1.0) evaluated to 1.0. The same applied to
llvm.vector.reduce.fminimum/fmaximum, which are expanded into chains of
llvm.minimum/maximum.

Use the generic LegalizerHelper::lowerFMinimumMaximum instead, which
emits fmin/fmax plus an unordered-compare select to propagate NaNs and a
G_IS_FPCLASS-based fixup for signed zeros. Both parts are omitted under
nnan and nsz respectively, so `nnan nsz` calls still produce a single
fmin/fmax.

Making the lowered code selectable required a few fixes elsewhere, since
it introduces virtual registers that the SPIR-V post-legalizer did not
know how to type:
- SPIRVPostLegalizer: deduce float types for G_FCONSTANT from the
  immediate, deduce G_SELECT types from the value operands instead of the
  condition, and also assign types to untyped COPY results (such as the
  final copy of a lowering into a newly created destination register).
  Previously these fell back to integer types or stayed untyped.
- SPIRVLegalizerInfo: the G_IS_FPCLASS custom lowering bitcasts its
  source immediately, so give the source a SPIR-V type if it doesn't have
  one yet.
---
 .../Target/SPIRV/SPIRVInstructionSelector.cpp |   2 -
 llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp  |  25 +-
 llvm/lib/Target/SPIRV/SPIRVPostLegalizer.cpp  |  10 +-
 .../SPV_EXT_long_vector/fminimum.ll           |  27 +++
 .../llvm-vector-reduce/fmaximum.ll            |  96 ++++++--
 .../llvm-vector-reduce/fminimum.ll            |  96 ++++++--
 .../llvm-intrinsics/fminimum-fmaximum.ll      | 215 ++++++++++++++++++
 .../SPIRV/llvm-intrinsics/fp-intrinsics.ll    |  12 +-
 .../llvm-vector-reduce/fmaximum.ll            |  54 ++++-
 .../llvm-vector-reduce/fminimum.ll            |  54 ++++-
 10 files changed, 534 insertions(+), 57 deletions(-)
 create mode 100644 llvm/test/CodeGen/SPIRV/extensions/SPV_EXT_long_vector/fminimum.ll
 create mode 100644 llvm/test/CodeGen/SPIRV/llvm-intrinsics/fminimum-fmaximum.ll

diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index 45cf5d9ab8635e..76362a30fad770 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -1174,10 +1174,8 @@ bool SPIRVInstructionSelector::spvSelect(Register ResVReg,
     return selectExtInst(ResVReg, ResType, I, CL::s_abs, GL::SAbs);
 
   case TargetOpcode::G_FMINNUM:
-  case TargetOpcode::G_FMINIMUM:
     return selectExtInst(ResVReg, ResType, I, CL::fmin, GL::NMin);
   case TargetOpcode::G_FMAXNUM:
-  case TargetOpcode::G_FMAXIMUM:
     return selectExtInst(ResVReg, ResType, I, CL::fmax, GL::NMax);
 
   case TargetOpcode::G_FCOPYSIGN:
diff --git a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
index b5d43a6074bc5e..38b54943ba25e9 100644
--- a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp
@@ -599,8 +599,6 @@ SPIRVLegalizerInfo::SPIRVLegalizerInfo(const SPIRVSubtarget &ST) {
                                G_FNEARBYINT,
                                G_INTRINSIC_ROUND,
                                G_INTRINSIC_TRUNC,
-                               G_FMINIMUM,
-                               G_FMAXIMUM,
                                G_INTRINSIC_ROUNDEVEN})
       .legalFor(allFloatScalars)
       .legalFor(allowedFloatVectorTypes)
@@ -610,6 +608,17 @@ SPIRVLegalizerInfo::SPIRVLegalizerInfo(const SPIRVSubtarget &ST) {
         .moreElementsToNextPow2(0);
   // clang-format on
 
+  // OpenCL.std fmin/fmax and GLSL.std.450 NMin/NMax implement IEEE 754-2008
+  // minNum/maxNum, which do not propagate NaNs and do not order signed zeros.
+  // Expand fminimum/fmaximum in terms of them.
+  getActionDefinitionsBuilder({G_FMINIMUM, G_FMAXIMUM})
+      .lowerFor(allFloatScalars)
+      .lowerFor(allowedFloatVectorTypes)
+      .fewerElementsIf(vectorElementCountIsGreaterThan(0, MaxVectorSize),
+                       LegalizeMutations::changeElementCountTo(
+                           0, ElementCount::getFixed(MaxVectorSize)))
+      .moreElementsToNextPow2(0);
+
   getActionDefinitionsBuilder(G_FCOPYSIGN)
       .legalForCartesianProduct(allFloatScalarsAndVectors,
                                 allFloatScalarsAndVectors);
@@ -1107,6 +1116,18 @@ bool SPIRVLegalizerInfo::legalizeIsFPClass(
   unsigned BitSize = SrcTy.getScalarSizeInBits();
   const fltSemantics &Semantics = getFltSemanticForLLT(SrcTy.getScalarType());
 
+  // If this G_IS_FPCLASS was created while lowering another instruction (e.g.
+  // G_FMINIMUM), its source may not have a SPIR-V type yet, but the OpBitcast
+  // below needs one.
+  if (!GR->getSPIRVTypeForVReg(SrcReg)) {
+    Type *LLVMSrcTy =
+        Type::getFloatingPointTy(MIRBuilder.getContext(), Semantics);
+    if (SrcTy.isVector())
+      LLVMSrcTy = VectorType::get(LLVMSrcTy, SrcTy.getElementCount());
+    setRegClassType(SrcReg, LLVMSrcTy, GR, MIRBuilder,
+                    SPIRV::AccessQualifier::ReadWrite, /*EmitIR=*/true);
+  }
+
   LLT IntTy = LLT::scalar(BitSize);
   Type *LLVMIntTy = IntegerType::get(MIRBuilder.getContext(), BitSize);
   if (SrcTy.isVector()) {
diff --git a/llvm/lib/Target/SPIRV/SPIRVPostLegalizer.cpp b/llvm/lib/Target/SPIRV/SPIRVPostLegalizer.cpp
index 8136b054f007b1..45476c2a49171b 100644
--- a/llvm/lib/Target/SPIRV/SPIRVPostLegalizer.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVPostLegalizer.cpp
@@ -312,6 +312,12 @@ static SPIRVTypeInst deduceResultTypeFromOperands(MachineInstr *I,
   case TargetOpcode::G_ZEXT:
   case TargetOpcode::G_TRUNC:
     return deduceIntTypeFromResult(ResVReg, MIB, GR);
+  case TargetOpcode::G_FCONSTANT:
+    return GR->getOrCreateSPIRVType(I->getOperand(1).getFPImm()->getType(), MIB,
+                                    SPIRV::AccessQualifier::ReadWrite,
+                                    /*EmitIR=*/true);
+  case TargetOpcode::G_SELECT:
+    return deduceTypeFromOperandRange(I, MIB, GR, 2, 4);
   case TargetOpcode::G_BUILD_VECTOR:
     return deduceTypeFromOperandRange(I, MIB, GR, 1, I->getNumOperands());
   case TargetOpcode::G_SHUFFLE_VECTOR:
@@ -424,7 +430,9 @@ static bool requiresSpirvType(MachineInstr &I, SPIRVGlobalRegistry *GR,
     return false;
   }
 
-  if (!I.isPreISelOpcode()) {
+  // Lowerings often copy their result into the original destination register,
+  // which is new and untyped if it was itself created during legalization.
+  if (!I.isPreISelOpcode() && !I.isCopy()) {
     LLVM_DEBUG(dbgs() << "Instruction is not a generic instruction.\n");
     return false;
   }
diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_EXT_long_vector/fminimum.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_EXT_long_vector/fminimum.ll
new file mode 100644
index 00000000000000..9d19b7a5e7dfc3
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_EXT_long_vector/fminimum.ll
@@ -0,0 +1,27 @@
+; RUN: llc -verify-machineinstrs -O0 --spirv-ext=+SPV_EXT_long_vector -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 --spirv-ext=+SPV_EXT_long_vector -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; llvm.minimum on <5 x float> is widened to <8 x float> before being lowered, so
+; the signed-zero check operates on newly created, widened operands.
+
+; CHECK-DAG: %[[#F32:]] = OpTypeFloat 32
+; CHECK-DAG: %[[#I32:]] = OpTypeInt 32 0
+; CHECK-DAG: %[[#V8F32:]] = OpTypeVector %[[#F32]] 8
+; CHECK-DAG: %[[#V8I32:]] = OpTypeVector %[[#I32]] 8
+
+; CHECK: OpFunction
+; CHECK: %[[#A:]] = OpCompositeConstruct %[[#V8F32]]
+; CHECK: %[[#B:]] = OpCompositeConstruct %[[#V8F32]]
+; CHECK: %[[#Min:]] = OpExtInst %[[#V8F32]] %[[#]] fmin %[[#A]] %[[#B]]
+; CHECK: %[[#Ord:]] = OpOrdered %[[#]] %[[#A]] %[[#B]]
+; CHECK: %[[#NaNSel:]] = OpSelect %[[#V8F32]] %[[#Ord]] %[[#Min]] %[[#]]
+; CHECK: %[[#IsZero:]] = OpFOrdEqual %[[#]] %[[#NaNSel]] %[[#]]
+; CHECK: %[[#]] = OpBitcast %[[#V8I32]] %[[#A]]
+; CHECK: %[[#]] = OpBitcast %[[#V8I32]] %[[#B]]
+; CHECK: %[[#Res:]] = OpSelect %[[#V8F32]] %[[#IsZero]] %[[#]] %[[#NaNSel]]
+; CHECK: OpCompositeExtract %[[#F32]] %[[#Res]] 0
+; CHECK: OpReturnValue
+define <5 x float> @minimum_v5f32(<5 x float> %a, <5 x float> %b) {
+  %r = call <5 x float> @llvm.minimum.v5f32(<5 x float> %a, <5 x float> %b)
+  ret <5 x float> %r
+}
diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_EXT_long_vector/llvm-vector-reduce/fmaximum.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_EXT_long_vector/llvm-vector-reduce/fmaximum.ll
index 4de10f5e02fe0a..e87228ed2f153d 100644
--- a/llvm/test/CodeGen/SPIRV/extensions/SPV_EXT_long_vector/llvm-vector-reduce/fmaximum.ll
+++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_EXT_long_vector/llvm-vector-reduce/fmaximum.ll
@@ -38,22 +38,86 @@ entry:
 ; CHECK: %[[Vec17FloatItem14:.*]] = OpCompositeExtract %[[Float]] %[[ParamVec17Float]] 14
 ; CHECK: %[[Vec17FloatItem15:.*]] = OpCompositeExtract %[[Float]] %[[ParamVec17Float]] 15
 ; CHECK: %[[Vec17FloatItem16:.*]] = OpCompositeExtract %[[Float]] %[[ParamVec17Float]] 16
-; CHECK: %[[Vec17FloatR1:.*]] = OpExtInst %[[Float]] %[[#]] fmax %[[Vec17FloatItem0]] %[[Vec17FloatItem1]]
-; CHECK: %[[Vec17FloatR2:.*]] = OpExtInst %[[Float]] %[[#]] fmax %[[Vec17FloatR1]] %[[Vec17FloatItem2]]
-; CHECK: %[[Vec17FloatR3:.*]] = OpExtInst %[[Float]] %[[#]] fmax %[[Vec17FloatR2]] %[[Vec17FloatItem3]]
-; CHECK: %[[Vec17FloatR4:.*]] = OpExtInst %[[Float]] %[[#]] fmax %[[Vec17FloatR3]] %[[Vec17FloatItem4]]
-; CHECK: %[[Vec17FloatR5:.*]] = OpExtInst %[[Float]] %[[#]] fmax %[[Vec17FloatR4]] %[[Vec17FloatItem5]]
-; CHECK: %[[Vec17FloatR6:.*]] = OpExtInst %[[Float]] %[[#]] fmax %[[Vec17FloatR5]] %[[Vec17FloatItem6]]
-; CHECK: %[[Vec17FloatR7:.*]] = OpExtInst %[[Float]] %[[#]] fmax %[[Vec17FloatR6]] %[[Vec17FloatItem7]]
-; CHECK: %[[Vec17FloatR8:.*]] = OpExtInst %[[Float]] %[[#]] fmax %[[Vec17FloatR7]] %[[Vec17FloatItem8]]
-; CHECK: %[[Vec17FloatR9:.*]] = OpExtInst %[[Float]] %[[#]] fmax %[[Vec17FloatR8]] %[[Vec17FloatItem9]]
-; CHECK: %[[Vec17FloatR10:.*]] = OpExtInst %[[Float]] %[[#]] fmax %[[Vec17FloatR9]] %[[Vec17FloatItem10]]
-; CHECK: %[[Vec17FloatR11:.*]] = OpExtInst %[[Float]] %[[#]] fmax %[[Vec17FloatR10]] %[[Vec17FloatItem11]]
-; CHECK: %[[Vec17FloatR12:.*]] = OpExtInst %[[Float]] %[[#]] fmax %[[Vec17FloatR11]] %[[Vec17FloatItem12]]
-; CHECK: %[[Vec17FloatR13:.*]] = OpExtInst %[[Float]] %[[#]] fmax %[[Vec17FloatR12]] %[[Vec17FloatItem13]]
-; CHECK: %[[Vec17FloatR14:.*]] = OpExtInst %[[Float]] %[[#]] fmax %[[Vec17FloatR13]] %[[Vec17FloatItem14]]
-; CHECK: %[[Vec17FloatR15:.*]] = OpExtInst %[[Float]] %[[#]] fmax %[[Vec17FloatR14]] %[[Vec17FloatItem15]]
-; CHECK: %[[Vec17FloatR16:.*]] = OpExtInst %[[Float]] %[[#]] fmax %[[Vec17FloatR15]] %[[Vec17FloatItem16]]
+; CHECK: %[[Vec17FloatR1MinMax:.*]] = OpExtInst %[[Float]] %[[#]] fmax %[[Vec17FloatItem0]] %[[Vec17FloatItem1]]
+; CHECK: %[[Vec17FloatR1Ord:.*]] = OpOrdered %[[#]] %[[Vec17FloatItem0]] %[[Vec17FloatItem1]]
+; CHECK: %[[Vec17FloatR1NaN:.*]] = OpSelect %[[Float]] %[[Vec17FloatR1Ord]] %[[Vec17FloatR1MinMax]] %[[#]]
+; CHECK: %[[Vec17FloatR1IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec17FloatR1NaN]] %[[#]]
+; CHECK: %[[Vec17FloatR1:.*]] = OpSelect %[[Float]] %[[Vec17FloatR1IsZero]] %[[#]] %[[Vec17FloatR1NaN]]
+; CHECK: %[[Vec17FloatR2MinMax:.*]] = OpExtInst %[[Float]] %[[#]] fmax %[[Vec17FloatR1]] %[[Vec17FloatItem2]]
+; CHECK: %[[Vec17FloatR2Ord:.*]] = OpOrdered %[[#]] %[[Vec17FloatR1]] %[[Vec17FloatItem2]]
+; CHECK: %[[Vec17FloatR2NaN:.*]] = OpSelect %[[Float]] %[[Vec17FloatR2Ord]] %[[Vec17FloatR2MinMax]] %[[#]]
+; CHECK: %[[Vec17FloatR2IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec17FloatR2NaN]] %[[#]]
+; CHECK: %[[Vec17FloatR2:.*]] = OpSelect %[[Float]] %[[Vec17FloatR2IsZero]] %[[#]] %[[Vec17FloatR2NaN]]
+; CHECK: %[[Vec17FloatR3MinMax:.*]] = OpExtInst %[[Float]] %[[#]] fmax %[[Vec17FloatR2]] %[[Vec17FloatItem3]]
+; CHECK: %[[Vec17FloatR3Ord:.*]] = OpOrdered %[[#]] %[[Vec17FloatR2]] %[[Vec17FloatItem3]]
+; CHECK: %[[Vec17FloatR3NaN:.*]] = OpSelect %[[Float]] %[[Vec17FloatR3Ord]] %[[Vec17FloatR3MinMax]] %[[#]]
+; CHECK: %[[Vec17FloatR3IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec17FloatR3NaN]] %[[#]]
+; CHECK: %[[Vec17FloatR3:.*]] = OpSelect %[[Float]] %[[Vec17FloatR3IsZero]] %[[#]] %[[Vec17FloatR3NaN]]
+; CHECK: %[[Vec17FloatR4MinMax:.*]] = OpExtInst %[[Float]] %[[#]] fmax %[[Vec17FloatR3]] %[[Vec17FloatItem4]]
+; CHECK: %[[Vec17FloatR4Ord:.*]] = OpOrdered %[[#]] %[[Vec17FloatR3]] %[[Vec17FloatItem4]]
+; CHECK: %[[Vec17FloatR4NaN:.*]] = OpSelect %[[Float]] %[[Vec17FloatR4Ord]] %[[Vec17FloatR4MinMax]] %[[#]]
+; CHECK: %[[Vec17FloatR4IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec17FloatR4NaN]] %[[#]]
+; CHECK: %[[Vec17FloatR4:.*]] = OpSelect %[[Float]] %[[Vec17FloatR4IsZero]] %[[#]] %[[Vec17FloatR4NaN]]
+; CHECK: %[[Vec17FloatR5MinMax:.*]] = OpExtInst %[[Float]] %[[#]] fmax %[[Vec17FloatR4]] %[[Vec17FloatItem5]]
+; CHECK: %[[Vec17FloatR5Ord:.*]] = OpOrdered %[[#]] %[[Vec17FloatR4]] %[[Vec17FloatItem5]]
+; CHECK: %[[Vec17FloatR5NaN:.*]] = OpSelect %[[Float]] %[[Vec17FloatR5Ord]] %[[Vec17FloatR5MinMax]] %[[#]]
+; CHECK: %[[Vec17FloatR5IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec17FloatR5NaN]] %[[#]]
+; CHECK: %[[Vec17FloatR5:.*]] = OpSelect %[[Float]] %[[Vec17FloatR5IsZero]] %[[#]] %[[Vec17FloatR5NaN]]
+; CHECK: %[[Vec17FloatR6MinMax:.*]] = OpExtInst %[[Float]] %[[#]] fmax %[[Vec17FloatR5]] %[[Vec17FloatItem6]]
+; CHECK: %[[Vec17FloatR6Ord:.*]] = OpOrdered %[[#]] %[[Vec17FloatR5]] %[[Vec17FloatItem6]]
+; CHECK: %[[Vec17FloatR6NaN:.*]] = OpSelect %[[Float]] %[[Vec17FloatR6Ord]] %[[Vec17FloatR6MinMax]] %[[#]]
+; CHECK: %[[Vec17FloatR6IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec17FloatR6NaN]] %[[#]]
+; CHECK: %[[Vec17FloatR6:.*]] = OpSelect %[[Float]] %[[Vec17FloatR6IsZero]] %[[#]] %[[Vec17FloatR6NaN]]
+; CHECK: %[[Vec17FloatR7MinMax:.*]] = OpExtInst %[[Float]] %[[#]] fmax %[[Vec17FloatR6]] %[[Vec17FloatItem7]]
+; CHECK: %[[Vec17FloatR7Ord:.*]] = OpOrdered %[[#]] %[[Vec17FloatR6]] %[[Vec17FloatItem7]]
+; CHECK: %[[Vec17FloatR7NaN:.*]] = OpSelect %[[Float]] %[[Vec17FloatR7Ord]] %[[Vec17FloatR7MinMax]] %[[#]]
+; CHECK: %[[Vec17FloatR7IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec17FloatR7NaN]] %[[#]]
+; CHECK: %[[Vec17FloatR7:.*]] = OpSelect %[[Float]] %[[Vec17FloatR7IsZero]] %[[#]] %[[Vec17FloatR7NaN]]
+; CHECK: %[[Vec17FloatR8MinMax:.*]] = OpExtInst %[[Float]] %[[#]] fmax %[[Vec17FloatR7]] %[[Vec17FloatItem8]]
+; CHECK: %[[Vec17FloatR8Ord:.*]] = OpOrdered %[[#]] %[[Vec17FloatR7]] %[[Vec17FloatItem8]]
+; CHECK: %[[Vec17FloatR8NaN:.*]] = OpSelect %[[Float]] %[[Vec17FloatR8Ord]] %[[Vec17FloatR8MinMax]] %[[#]]
+; CHECK: %[[Vec17FloatR8IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec17FloatR8NaN]] %[[#]]
+; CHECK: %[[Vec17FloatR8:.*]] = OpSelect %[[Float]] %[[Vec17FloatR8IsZero]] %[[#]] %[[Vec17FloatR8NaN]]
+; CHECK: %[[Vec17FloatR9MinMax:.*]] = OpExtInst %[[Float]] %[[#]] fmax %[[Vec17FloatR8]] %[[Vec17FloatItem9]]
+; CHECK: %[[Vec17FloatR9Ord:.*]] = OpOrdered %[[#]] %[[Vec17FloatR8]] %[[Vec17FloatItem9]]
+; CHECK: %[[Vec17FloatR9NaN:.*]] = OpSelect %[[Float]] %[[Vec17FloatR9Ord]] %[[Vec17FloatR9MinMax]] %[[#]]
+; CHECK: %[[Vec17FloatR9IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec17FloatR9NaN]] %[[#]]
+; CHECK: %[[Vec17FloatR9:.*]] = OpSelect %[[Float]] %[[Vec17FloatR9IsZero]] %[[#]] %[[Vec17FloatR9NaN]]
+; CHECK: %[[Vec17FloatR10MinMax:.*]] = OpExtInst %[[Float]] %[[#]] fmax %[[Vec17FloatR9]] %[[Vec17FloatItem10]]
+; CHECK: %[[Vec17FloatR10Ord:.*]] = OpOrdered %[[#]] %[[Vec17FloatR9]] %[[Vec17FloatItem10]]
+; CHECK: %[[Vec17FloatR10NaN:.*]] = OpSelect %[[Float]] %[[Vec17FloatR10Ord]] %[[Vec17FloatR10MinMax]] %[[#]]
+; CHECK: %[[Vec17FloatR10IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec17FloatR10NaN]] %[[#]]
+; CHECK: %[[Vec17FloatR10:.*]] = OpSelect %[[Float]] %[[Vec17FloatR10IsZero]] %[[#]] %[[Vec17FloatR10NaN]]
+; CHECK: %[[Vec17FloatR11MinMax:.*]] = OpExtInst %[[Float]] %[[#]] fmax %[[Vec17FloatR10]] %[[Vec17FloatItem11]]
+; CHECK: %[[Vec17FloatR11Ord:.*]] = OpOrdered %[[#]] %[[Vec17FloatR10]] %[[Vec17FloatItem11]]
+; CHECK: %[[Vec17FloatR11NaN:.*]] = OpSelect %[[Float]] %[[Vec17FloatR11Ord]] %[[Vec17FloatR11MinMax]] %[[#]]
+; CHECK: %[[Vec17FloatR11IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec17FloatR11NaN]] %[[#]]
+; CHECK: %[[Vec17FloatR11:.*]] = OpSelect %[[Float]] %[[Vec17FloatR11IsZero]] %[[#]] %[[Vec17FloatR11NaN]]
+; CHECK: %[[Vec17FloatR12MinMax:.*]] = OpExtInst %[[Float]] %[[#]] fmax %[[Vec17FloatR11]] %[[Vec17FloatItem12]]
+; CHECK: %[[Vec17FloatR12Ord:.*]] = OpOrdered %[[#]] %[[Vec17FloatR11]] %[[Vec17FloatItem12]]
+; CHECK: %[[Vec17FloatR12NaN:.*]] = OpSelect %[[Float]] %[[Vec17FloatR12Ord]] %[[Vec17FloatR12MinMax]] %[[#]]
+; CHECK: %[[Vec17FloatR12IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec17FloatR12NaN]] %[[#]]
+; CHECK: %[[Vec17FloatR12:.*]] = OpSelect %[[Float]] %[[Vec17FloatR12IsZero]] %[[#]] %[[Vec17FloatR12NaN]]
+; CHECK: %[[Vec17FloatR13MinMax:.*]] = OpExtInst %[[Float]] %[[#]] fmax %[[Vec17FloatR12]] %[[Vec17FloatItem13]]
+; CHECK: %[[Vec17FloatR13Ord:.*]] = OpOrdered %[[#]] %[[Vec17FloatR12]] %[[Vec17FloatItem13]]
+; CHECK: %[[Vec17FloatR13NaN:.*]] = OpSelect %[[Float]] %[[Vec17FloatR13Ord]] %[[Vec17FloatR13MinMax]] %[[#]]
+; CHECK: %[[Vec17FloatR13IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec17FloatR13NaN]] %[[#]]
+; CHECK: %[[Vec17FloatR13:.*]] = OpSelect %[[Float]] %[[Vec17FloatR13IsZero]] %[[#]] %[[Vec17FloatR13NaN]]
+; CHECK: %[[Vec17FloatR14MinMax:.*]] = OpExtInst %[[Float]] %[[#]] fmax %[[Vec17FloatR13]] %[[Vec17FloatItem14]]
+; CHECK: %[[Vec17FloatR14Ord:.*]] = OpOrdered %[[#]] %[[Vec17FloatR13]] %[[Vec17FloatItem14]]
+; CHECK: %[[Vec17FloatR14NaN:.*]] = OpSelect %[[Float]] %[[Vec17FloatR14Ord]] %[[Vec17FloatR14MinMax]] %[[#]]
+; CHECK: %[[Vec17FloatR14IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec17FloatR14NaN]] %[[#]]
+; CHECK: %[[Vec17FloatR14:.*]] = OpSelect %[[Float]] %[[Vec17FloatR14IsZero]] %[[#]] %[[Vec17FloatR14NaN]]
+; CHECK: %[[Vec17FloatR15MinMax:.*]] = OpExtInst %[[Float]] %[[#]] fmax %[[Vec17FloatR14]] %[[Vec17FloatItem15]]
+; CHECK: %[[Vec17FloatR15Ord:.*]] = OpOrdered %[[#]] %[[Vec17FloatR14]] %[[Vec17FloatItem15]]
+; CHECK: %[[Vec17FloatR15NaN:.*]] = OpSelect %[[Float]] %[[Vec17FloatR15Ord]] %[[Vec17FloatR15MinMax]] %[[#]]
+; CHECK: %[[Vec17FloatR15IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec17FloatR15NaN]] %[[#]]
+; CHECK: %[[Vec17FloatR15:.*]] = OpSelect %[[Float]] %[[Vec17FloatR15IsZero]] %[[#]] %[[Vec17FloatR15NaN]]
+; CHECK: %[[Vec17FloatR16MinMax:.*]] = OpExtInst %[[Float]] %[[#]] fmax %[[Vec17FloatR15]] %[[Vec17FloatItem16]]
+; CHECK: %[[Vec17FloatR16Ord:.*]] = OpOrdered %[[#]] %[[Vec17FloatR15]] %[[Vec17FloatItem16]]
+; CHECK: %[[Vec17FloatR16NaN:.*]] = OpSelect %[[Float]] %[[Vec17FloatR16Ord]] %[[Vec17FloatR16MinMax]] %[[#]]
+; CHECK: %[[Vec17FloatR16IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec17FloatR16NaN]] %[[#]]
+; CHECK: %[[Vec17FloatR16:.*]] = OpSelect %[[Float]] %[[Vec17FloatR16IsZero]] %[[#]] %[[Vec17FloatR16NaN]]
 ; CHECK: OpReturnValue %[[Vec17FloatR16]]
 ; CHECK: OpFunctionEnd
 define spir_func float @test_vector_reduce_fmaximum_v17f32(<17 x float> %v) {
diff --git a/llvm/test/CodeGen/SPIRV/extensions/SPV_EXT_long_vector/llvm-vector-reduce/fminimum.ll b/llvm/test/CodeGen/SPIRV/extensions/SPV_EXT_long_vector/llvm-vector-reduce/fminimum.ll
index ccf43bdca3e9c2..df5be4d8a9250f 100644
--- a/llvm/test/CodeGen/SPIRV/extensions/SPV_EXT_long_vector/llvm-vector-reduce/fminimum.ll
+++ b/llvm/test/CodeGen/SPIRV/extensions/SPV_EXT_long_vector/llvm-vector-reduce/fminimum.ll
@@ -38,22 +38,86 @@ entry:
 ; CHECK: %[[Vec17FloatItem14:.*]] = OpCompositeExtract %[[Float]] %[[ParamVec17Float]] 14
 ; CHECK: %[[Vec17FloatItem15:.*]] = OpCompositeExtract %[[Float]] %[[ParamVec17Float]] 15
 ; CHECK: %[[Vec17FloatItem16:.*]] = OpCompositeExtract %[[Float]] %[[ParamVec17Float]] 16
-; CHECK: %[[Vec17FloatR1:.*]] = OpExtInst %[[Float]] %[[#]] fmin %[[Vec17FloatItem0]] %[[Vec17FloatItem1]]
-; CHECK: %[[Vec17FloatR2:.*]] = OpExtInst %[[Float]] %[[#]] fmin %[[Vec17FloatR1]] %[[Vec17FloatItem2]]
-; CHECK: %[[Vec17FloatR3:.*]] = OpExtInst %[[Float]] %[[#]] fmin %[[Vec17FloatR2]] %[[Vec17FloatItem3]]
-; CHECK: %[[Vec17FloatR4:.*]] = OpExtInst %[[Float]] %[[#]] fmin %[[Vec17FloatR3]] %[[Vec17FloatItem4]]
-; CHECK: %[[Vec17FloatR5:.*]] = OpExtInst %[[Float]] %[[#]] fmin %[[Vec17FloatR4]] %[[Vec17FloatItem5]]
-; CHECK: %[[Vec17FloatR6:.*]] = OpExtInst %[[Float]] %[[#]] fmin %[[Vec17FloatR5]] %[[Vec17FloatItem6]]
-; CHECK: %[[Vec17FloatR7:.*]] = OpExtInst %[[Float]] %[[#]] fmin %[[Vec17FloatR6]] %[[Vec17FloatItem7]]
-; CHECK: %[[Vec17FloatR8:.*]] = OpExtInst %[[Float]] %[[#]] fmin %[[Vec17FloatR7]] %[[Vec17FloatItem8]]
-; CHECK: %[[Vec17FloatR9:.*]] = OpExtInst %[[Float]] %[[#]] fmin %[[Vec17FloatR8]] %[[Vec17FloatItem9]]
-; CHECK: %[[Vec17FloatR10:.*]] = OpExtInst %[[Float]] %[[#]] fmin %[[Vec17FloatR9]] %[[Vec17FloatItem10]]
-; CHECK: %[[Vec17FloatR11:.*]] = OpExtInst %[[Float]] %[[#]] fmin %[[Vec17FloatR10]] %[[Vec17FloatItem11]]
-; CHECK: %[[Vec17FloatR12:.*]] = OpExtInst %[[Float]] %[[#]] fmin %[[Vec17FloatR11]] %[[Vec17FloatItem12]]
-; CHECK: %[[Vec17FloatR13:.*]] = OpExtInst %[[Float]] %[[#]] fmin %[[Vec17FloatR12]] %[[Vec17FloatItem13]]
-; CHECK: %[[Vec17FloatR14:.*]] = OpExtInst %[[Float]] %[[#]] fmin %[[Vec17FloatR13]] %[[Vec17FloatItem14]]
-; CHECK: %[[Vec17FloatR15:.*]] = OpExtInst %[[Float]] %[[#]] fmin %[[Vec17FloatR14]] %[[Vec17FloatItem15]]
-; CHECK: %[[Vec17FloatR16:.*]] = OpExtInst %[[Float]] %[[#]] fmin %[[Vec17FloatR15]] %[[Vec17FloatItem16]]
+; CHECK: %[[Vec17FloatR1MinMax:.*]] = OpExtInst %[[Float]] %[[#]] fmin %[[Vec17FloatItem0]] %[[Vec17FloatItem1]]
+; CHECK: %[[Vec17FloatR1Ord:.*]] = OpOrdered %[[#]] %[[Vec17FloatItem0]] %[[Vec17FloatItem1]]
+; CHECK: %[[Vec17FloatR1NaN:.*]] = OpSelect %[[Float]] %[[Vec17FloatR1Ord]] %[[Vec17FloatR1MinMax]] %[[#]]
+; CHECK: %[[Vec17FloatR1IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec17FloatR1NaN]] %[[#]]
+; CHECK: %[[Vec17FloatR1:.*]] = OpSelect %[[Float]] %[[Vec17FloatR1IsZero]] %[[#]] %[[Vec17FloatR1NaN]]
+; CHECK: %[[Vec17FloatR2MinMax:.*]] = OpExtInst %[[Float]] %[[#]] fmin %[[Vec17FloatR1]] %[[Vec17FloatItem2]]
+; CHECK: %[[Vec17FloatR2Ord:.*]] = OpOrdered %[[#]] %[[Vec17FloatR1]] %[[Vec17FloatItem2]]
+; CHECK: %[[Vec17FloatR2NaN:.*]] = OpSelect %[[Float]] %[[Vec17FloatR2Ord]] %[[Vec17FloatR2MinMax]] %[[#]]
+; CHECK: %[[Vec17FloatR2IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec17FloatR2NaN]] %[[#]]
+; CHECK: %[[Vec17FloatR2:.*]] = OpSelect %[[Float]] %[[Vec17FloatR2IsZero]] %[[#]] %[[Vec17FloatR2NaN]]
+; CHECK: %[[Vec17FloatR3MinMax:.*]] = OpExtInst %[[Float]] %[[#]] fmin %[[Vec17FloatR2]] %[[Vec17FloatItem3]]
+; CHECK: %[[Vec17FloatR3Ord:.*]] = OpOrdered %[[#]] %[[Vec17FloatR2]] %[[Vec17FloatItem3]]
+; CHECK: %[[Vec17FloatR3NaN:.*]] = OpSelect %[[Float]] %[[Vec17FloatR3Ord]] %[[Vec17FloatR3MinMax]] %[[#]]
+; CHECK: %[[Vec17FloatR3IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec17FloatR3NaN]] %[[#]]
+; CHECK: %[[Vec17FloatR3:.*]] = OpSelect %[[Float]] %[[Vec17FloatR3IsZero]] %[[#]] %[[Vec17FloatR3NaN]]
+; CHECK: %[[Vec17FloatR4MinMax:.*]] = OpExtInst %[[Float]] %[[#]] fmin %[[Vec17FloatR3]] %[[Vec17FloatItem4]]
+; CHECK: %[[Vec17FloatR4Ord:.*]] = OpOrdered %[[#]] %[[Vec17FloatR3]] %[[Vec17FloatItem4]]
+; CHECK: %[[Vec17FloatR4NaN:.*]] = OpSelect %[[Float]] %[[Vec17FloatR4Ord]] %[[Vec17FloatR4MinMax]] %[[#]]
+; CHECK: %[[Vec17FloatR4IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec17FloatR4NaN]] %[[#]]
+; CHECK: %[[Vec17FloatR4:.*]] = OpSelect %[[Float]] %[[Vec17FloatR4IsZero]] %[[#]] %[[Vec17FloatR4NaN]]
+; CHECK: %[[Vec17FloatR5MinMax:.*]] = OpExtInst %[[Float]] %[[#]] fmin %[[Vec17FloatR4]] %[[Vec17FloatItem5]]
+; CHECK: %[[Vec17FloatR5Ord:.*]] = OpOrdered %[[#]] %[[Vec17FloatR4]] %[[Vec17FloatItem5]]
+; CHECK: %[[Vec17FloatR5NaN:.*]] = OpSelect %[[Float]] %[[Vec17FloatR5Ord]] %[[Vec17FloatR5MinMax]] %[[#]]
+; CHECK: %[[Vec17FloatR5IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec17FloatR5NaN]] %[[#]]
+; CHECK: %[[Vec17FloatR5:.*]] = OpSelect %[[Float]] %[[Vec17FloatR5IsZero]] %[[#]] %[[Vec17FloatR5NaN]]
+; CHECK: %[[Vec17FloatR6MinMax:.*]] = OpExtInst %[[Float]] %[[#]] fmin %[[Vec17FloatR5]] %[[Vec17FloatItem6]]
+; CHECK: %[[Vec17FloatR6Ord:.*]] = OpOrdered %[[#]] %[[Vec17FloatR5]] %[[Vec17FloatItem6]]
+; CHECK: %[[Vec17FloatR6NaN:.*]] = OpSelect %[[Float]] %[[Vec17FloatR6Ord]] %[[Vec17FloatR6MinMax]] %[[#]]
+; CHECK: %[[Vec17FloatR6IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec17FloatR6NaN]] %[[#]]
+; CHECK: %[[Vec17FloatR6:.*]] = OpSelect %[[Float]] %[[Vec17FloatR6IsZero]] %[[#]] %[[Vec17FloatR6NaN]]
+; CHECK: %[[Vec17FloatR7MinMax:.*]] = OpExtInst %[[Float]] %[[#]] fmin %[[Vec17FloatR6]] %[[Vec17FloatItem7]]
+; CHECK: %[[Vec17FloatR7Ord:.*]] = OpOrdered %[[#]] %[[Vec17FloatR6]] %[[Vec17FloatItem7]]
+; CHECK: %[[Vec17FloatR7NaN:.*]] = OpSelect %[[Float]] %[[Vec17FloatR7Ord]] %[[Vec17FloatR7MinMax]] %[[#]]
+; CHECK: %[[Vec17FloatR7IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec17FloatR7NaN]] %[[#]]
+; CHECK: %[[Vec17FloatR7:.*]] = OpSelect %[[Float]] %[[Vec17FloatR7IsZero]] %[[#]] %[[Vec17FloatR7NaN]]
+; CHECK: %[[Vec17FloatR8MinMax:.*]] = OpExtInst %[[Float]] %[[#]] fmin %[[Vec17FloatR7]] %[[Vec17FloatItem8]]
+; CHECK: %[[Vec17FloatR8Ord:.*]] = OpOrdered %[[#]] %[[Vec17FloatR7]] %[[Vec17FloatItem8]]
+; CHECK: %[[Vec17FloatR8NaN:.*]] = OpSelect %[[Float]] %[[Vec17FloatR8Ord]] %[[Vec17FloatR8MinMax]] %[[#]]
+; CHECK: %[[Vec17FloatR8IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec17FloatR8NaN]] %[[#]]
+; CHECK: %[[Vec17FloatR8:.*]] = OpSelect %[[Float]] %[[Vec17FloatR8IsZero]] %[[#]] %[[Vec17FloatR8NaN]]
+; CHECK: %[[Vec17FloatR9MinMax:.*]] = OpExtInst %[[Float]] %[[#]] fmin %[[Vec17FloatR8]] %[[Vec17FloatItem9]]
+; CHECK: %[[Vec17FloatR9Ord:.*]] = OpOrdered %[[#]] %[[Vec17FloatR8]] %[[Vec17FloatItem9]]
+; CHECK: %[[Vec17FloatR9NaN:.*]] = OpSelect %[[Float]] %[[Vec17FloatR9Ord]] %[[Vec17FloatR9MinMax]] %[[#]]
+; CHECK: %[[Vec17FloatR9IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec17FloatR9NaN]] %[[#]]
+; CHECK: %[[Vec17FloatR9:.*]] = OpSelect %[[Float]] %[[Vec17FloatR9IsZero]] %[[#]] %[[Vec17FloatR9NaN]]
+; CHECK: %[[Vec17FloatR10MinMax:.*]] = OpExtInst %[[Float]] %[[#]] fmin %[[Vec17FloatR9]] %[[Vec17FloatItem10]]
+; CHECK: %[[Vec17FloatR10Ord:.*]] = OpOrdered %[[#]] %[[Vec17FloatR9]] %[[Vec17FloatItem10]]
+; CHECK: %[[Vec17FloatR10NaN:.*]] = OpSelect %[[Float]] %[[Vec17FloatR10Ord]] %[[Vec17FloatR10MinMax]] %[[#]]
+; CHECK: %[[Vec17FloatR10IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec17FloatR10NaN]] %[[#]]
+; CHECK: %[[Vec17FloatR10:.*]] = OpSelect %[[Float]] %[[Vec17FloatR10IsZero]] %[[#]] %[[Vec17FloatR10NaN]]
+; CHECK: %[[Vec17FloatR11MinMax:.*]] = OpExtInst %[[Float]] %[[#]] fmin %[[Vec17FloatR10]] %[[Vec17FloatItem11]]
+; CHECK: %[[Vec17FloatR11Ord:.*]] = OpOrdered %[[#]] %[[Vec17FloatR10]] %[[Vec17FloatItem11]]
+; CHECK: %[[Vec17FloatR11NaN:.*]] = OpSelect %[[Float]] %[[Vec17FloatR11Ord]] %[[Vec17FloatR11MinMax]] %[[#]]
+; CHECK: %[[Vec17FloatR11IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec17FloatR11NaN]] %[[#]]
+; CHECK: %[[Vec17FloatR11:.*]] = OpSelect %[[Float]] %[[Vec17FloatR11IsZero]] %[[#]] %[[Vec17FloatR11NaN]]
+; CHECK: %[[Vec17FloatR12MinMax:.*]] = OpExtInst %[[Float]] %[[#]] fmin %[[Vec17FloatR11]] %[[Vec17FloatItem12]]
+; CHECK: %[[Vec17FloatR12Ord:.*]] = OpOrdered %[[#]] %[[Vec17FloatR11]] %[[Vec17FloatItem12]]
+; CHECK: %[[Vec17FloatR12NaN:.*]] = OpSelect %[[Float]] %[[Vec17FloatR12Ord]] %[[Vec17FloatR12MinMax]] %[[#]]
+; CHECK: %[[Vec17FloatR12IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec17FloatR12NaN]] %[[#]]
+; CHECK: %[[Vec17FloatR12:.*]] = OpSelect %[[Float]] %[[Vec17FloatR12IsZero]] %[[#]] %[[Vec17FloatR12NaN]]
+; CHECK: %[[Vec17FloatR13MinMax:.*]] = OpExtInst %[[Float]] %[[#]] fmin %[[Vec17FloatR12]] %[[Vec17FloatItem13]]
+; CHECK: %[[Vec17FloatR13Ord:.*]] = OpOrdered %[[#]] %[[Vec17FloatR12]] %[[Vec17FloatItem13]]
+; CHECK: %[[Vec17FloatR13NaN:.*]] = OpSelect %[[Float]] %[[Vec17FloatR13Ord]] %[[Vec17FloatR13MinMax]] %[[#]]
+; CHECK: %[[Vec17FloatR13IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec17FloatR13NaN]] %[[#]]
+; CHECK: %[[Vec17FloatR13:.*]] = OpSelect %[[Float]] %[[Vec17FloatR13IsZero]] %[[#]] %[[Vec17FloatR13NaN]]
+; CHECK: %[[Vec17FloatR14MinMax:.*]] = OpExtInst %[[Float]] %[[#]] fmin %[[Vec17FloatR13]] %[[Vec17FloatItem14]]
+; CHECK: %[[Vec17FloatR14Ord:.*]] = OpOrdered %[[#]] %[[Vec17FloatR13]] %[[Vec17FloatItem14]]
+; CHECK: %[[Vec17FloatR14NaN:.*]] = OpSelect %[[Float]] %[[Vec17FloatR14Ord]] %[[Vec17FloatR14MinMax]] %[[#]]
+; CHECK: %[[Vec17FloatR14IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec17FloatR14NaN]] %[[#]]
+; CHECK: %[[Vec17FloatR14:.*]] = OpSelect %[[Float]] %[[Vec17FloatR14IsZero]] %[[#]] %[[Vec17FloatR14NaN]]
+; CHECK: %[[Vec17FloatR15MinMax:.*]] = OpExtInst %[[Float]] %[[#]] fmin %[[Vec17FloatR14]] %[[Vec17FloatItem15]]
+; CHECK: %[[Vec17FloatR15Ord:.*]] = OpOrdered %[[#]] %[[Vec17FloatR14]] %[[Vec17FloatItem15]]
+; CHECK: %[[Vec17FloatR15NaN:.*]] = OpSelect %[[Float]] %[[Vec17FloatR15Ord]] %[[Vec17FloatR15MinMax]] %[[#]]
+; CHECK: %[[Vec17FloatR15IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec17FloatR15NaN]] %[[#]]
+; CHECK: %[[Vec17FloatR15:.*]] = OpSelect %[[Float]] %[[Vec17FloatR15IsZero]] %[[#]] %[[Vec17FloatR15NaN]]
+; CHECK: %[[Vec17FloatR16MinMax:.*]] = OpExtInst %[[Float]] %[[#]] fmin %[[Vec17FloatR15]] %[[Vec17FloatItem16]]
+; CHECK: %[[Vec17FloatR16Ord:.*]] = OpOrdered %[[#]] %[[Vec17FloatR15]] %[[Vec17FloatItem16]]
+; CHECK: %[[Vec17FloatR16NaN:.*]] = OpSelect %[[Float]] %[[Vec17FloatR16Ord]] %[[Vec17FloatR16MinMax]] %[[#]]
+; CHECK: %[[Vec17FloatR16IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec17FloatR16NaN]] %[[#]]
+; CHECK: %[[Vec17FloatR16:.*]] = OpSelect %[[Float]] %[[Vec17FloatR16IsZero]] %[[#]] %[[Vec17FloatR16NaN]]
 ; CHECK: OpReturnValue %[[Vec17FloatR16]]
 ; CHECK: OpFunctionEnd
 define spir_func float @test_vector_reduce_fminimum_v17f32(<17 x float> %v) {
diff --git a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/fminimum-fmaximum.ll b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/fminimum-fmaximum.ll
new file mode 100644
index 00000000000000..86a7298a0cbdde
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/fminimum-fmaximum.ll
@@ -0,0 +1,215 @@
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s --check-prefixes=CHECK,CL
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefixes=CHECK,CL
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-vulkan %s -o - | FileCheck %s --check-prefixes=CHECK,VK
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan %s -o - -filetype=obj | spirv-val %}
+
+; llvm.minimum/llvm.maximum propagate NaNs and order -0.0 before +0.0, whereas
+; OpenCL.std fmin/fmax and GLSL.std.450 NMin/NMax return the non-NaN operand and
+; may return either zero. Check that the missing NaN propagation and signed-zero
+; handling are added, and dropped again under nnan and nsz.
+
+; CL-DAG: %[[#Ext:]] = OpExtInstImport "OpenCL.std"
+; VK-DAG: %[[#Ext:]] = OpExtInstImport "GLSL.std.450"
+; CHECK-DAG: %[[#Bool:]] = OpTypeBool
+; CHECK-DAG: %[[#False:]] = OpConstantFalse %[[#Bool]]
+; CHECK-DAG: %[[#F16:]] = OpTypeFloat 16
+; CHECK-DAG: %[[#F32:]] = OpTypeFloat 32
+; CHECK-DAG: %[[#F64:]] = OpTypeFloat 64
+; CHECK-DAG: %[[#I32:]] = OpTypeInt 32 0
+; CHECK-DAG: %[[#V2F32:]] = OpTypeVector %[[#F32]] 2
+; CHECK-DAG: %[[#V3F32:]] = OpTypeVector %[[#F32]] 3
+; CHECK-DAG: %[[#V4F32:]] = OpTypeVector %[[#F32]] 4
+; CHECK-DAG: %[[#V4Bool:]] = OpTypeVector %[[#Bool]] 4
+; CHECK-DAG: %[[#NaN16:]] = OpConstant %[[#F16]] 32256
+; CHECK-DAG: %[[#NaN32:]] = OpConstant %[[#F32]] 0x1.8p+128
+; CHECK-DAG: %[[#NaN64:]] = OpConstant %[[#F64]] 0x1.8p+1024
+; CL-DAG: %[[#Zero32:]] = OpConstantNull %[[#F32]]
+; VK-DAG: %[[#Zero32:]] = OpConstant %[[#F32]] 0{{$}}
+; CHECK-DAG: %[[#NegZeroBits32:]] = OpConstant %[[#I32]] 2147483648
+; CL-DAG: %[[#PosZeroBits32:]] = OpConstantNull %[[#I32]]
+; VK-DAG: %[[#PosZeroBits32:]] = OpConstant %[[#I32]] 0{{$}}
+
+; CHECK-LABEL: Begin function minimum_f32
+; CHECK: %[[#A:]] = OpFunctionParameter %[[#F32]]
+; CHECK: %[[#B:]] = OpFunctionParameter %[[#F32]]
+; CL: %[[#Min:]] = OpExtInst %[[#F32]] %[[#Ext]] fmin %[[#A]] %[[#B]]
+; VK: %[[#Min:]] = OpExtInst %[[#F32]] %[[#Ext]] NMin %[[#A]] %[[#B]]
+; CL: %[[#Ord:]] = OpOrdered %[[#Bool]] %[[#A]] %[[#B]]
+; VK: %[[#NanA:]] = OpIsNan %[[#Bool]] %[[#A]]
+; VK: %[[#NanB:]] = OpIsNan %[[#Bool]] %[[#B]]
+; VK: %[[#Uno:]] = OpLogicalOr %[[#Bool]] %[[#NanA]] %[[#NanB]]
+; VK: %[[#Ord:]] = OpLogicalNot %[[#Bool]] %[[#Uno]]
+; CHECK: %[[#NaNSel:]] = OpSelect %[[#F32]] %[[#Ord]] %[[#Min]] %[[#NaN32]]
+; CHECK: %[[#IsZero:]] = OpFOrdEqual %[[#Bool]] %[[#NaNSel]] %[[#Zero32]]
+; CHECK: %[[#ABits:]] = OpBitcast %[[#I32]] %[[#A]]
+; CHECK: %[[#ANegZero:]] = OpIEqual %[[#Bool]] %[[#ABits]] %[[#NegZeroBits32]]
+; CHECK: %[[#ACond:]] = OpLogicalOr %[[#Bool]] %[[#False]] %[[#ANegZero]]
+; CHECK: %[[#ASel:]] = OpSelect %[[#F32]] %[[#ACond]] %[[#A]] %[[#NaNSel]]
+; CHECK: %[[#BBits:]] = OpBitcast %[[#I32]] %[[#B]]
+; CHECK: %[[#BNegZero:]] = OpIEqual %[[#Bool]] %[[#BBits]] %[[#NegZeroBits32]]
+; CHECK: %[[#BCond:]] = OpLogicalOr %[[#Bool]] %[[#False]] %[[#BNegZero]]
+; CHECK: %[[#BSel:]] = OpSelect %[[#F32]] %[[#BCond]] %[[#B]] %[[#ASel]]
+; CHECK: %[[#Res:]] = OpSelect %[[#F32]] %[[#IsZero]] %[[#BSel]] %[[#NaNSel]]
+; CHECK: OpReturnValue %[[#Res]]
+define float @minimum_f32(float %a, float %b) {
+  %r = call float @llvm.minimum.f32(float %a, float %b)
+  ret float %r
+}
+
+; CHECK-LABEL: Begin function maximum_f32
+; CHECK: %[[#A:]] = OpFunctionParameter %[[#F32]]
+; CHECK: %[[#B:]] = OpFunctionParameter %[[#F32]]
+; CL: %[[#Max:]] = OpExtInst %[[#F32]] %[[#Ext]] fmax %[[#A]] %[[#B]]
+; VK: %[[#Max:]] = OpExtInst %[[#F32]] %[[#Ext]] NMax %[[#A]] %[[#B]]
+; CL: %[[#Ord:]] = OpOrdered %[[#Bool]] %[[#A]] %[[#B]]
+; VK: %[[#Ord:]] = OpLogicalNot %[[#Bool]]
+; CHECK: %[[#NaNSel:]] = OpSelect %[[#F32]] %[[#Ord]] %[[#Max]] %[[#NaN32]]
+; CHECK: %[[#IsZero:]] = OpFOrdEqual %[[#Bool]] %[[#NaNSel]] %[[#Zero32]]
+; CHECK: %[[#ABits:]] = OpBitcast %[[#I32]] %[[#A]]
+; CHECK: %[[#APosZero:]] = OpIEqual %[[#Bool]] %[[#ABits]] %[[#PosZeroBits32]]
+; CHECK: %[[#ACond:]] = OpLogicalOr %[[#Bool]] %[[#False]] %[[#APosZero]]
+; CHECK: %[[#ASel:]] = OpSelect %[[#F32]] %[[#ACond]] %[[#A]] %[[#NaNSel]]
+; CHECK: %[[#BBits:]] = OpBitcast %[[#I32]] %[[#B]]
+; CHECK: %[[#BPosZero:]] = OpIEqual %[[#Bool]] %[[#BBits]] %[[#PosZeroBits32]]
+; CHECK: %[[#BCond:]] = OpLogicalOr %[[#Bool]] %[[#False]] %[[#BPosZero]]
+; CHECK: %[[#BSel:]] = OpSelect %[[#F32]] %[[#BCond]] %[[#B]] %[[#ASel]]
+; CHECK: %[[#Res:]] = OpSelect %[[#F32]] %[[#IsZero]] %[[#BSel]] %[[#NaNSel]]
+; CHECK: OpReturnValue %[[#Res]]
+define float @maximum_f32(float %a, float %b) {
+  %r = call float @llvm.maximum.f32(float %a, float %b)
+  ret float %r
+}
+
+; With nnan, only the signed-zero handling remains.
+; CHECK-LABEL: Begin function minimum_f32_nnan
+; CHECK: %[[#A:]] = OpFunctionParameter %[[#F32]]
+; CHECK: %[[#B:]] = OpFunctionParameter %[[#F32]]
+; CL: %[[#Min:]] = OpExtInst %[[#F32]] %[[#Ext]] fmin %[[#A]] %[[#B]]
+; VK: %[[#Min:]] = OpExtInst %[[#F32]] %[[#Ext]] NMin %[[#A]] %[[#B]]
+; CHECK-NOT: OpOrdered
+; CHECK-NOT: OpIsNan
+; CHECK: %[[#IsZero:]] = OpFOrdEqual %[[#Bool]] %[[#Min]] %[[#Zero32]]
+; CHECK: %[[#Res:]] = OpSelect %[[#F32]] %[[#IsZero]] %[[#]] %[[#Min]]
+; CHECK: OpReturnValue %[[#Res]]
+define float @minimum_f32_nnan(float %a, float %b) {
+  %r = call nnan float @llvm.minimum.f32(float %a, float %b)
+  ret float %r
+}
+
+; With nsz, only the NaN propagation remains.
+; CHECK-LABEL: Begin function minimum_f32_nsz
+; CHECK: %[[#A:]] = OpFunctionParameter %[[#F32]]
+; CHECK: %[[#B:]] = OpFunctionParameter %[[#F32]]
+; CL: %[[#Min:]] = OpExtInst %[[#F32]] %[[#Ext]] fmin %[[#A]] %[[#B]]
+; VK: %[[#Min:]] = OpExtInst %[[#F32]] %[[#Ext]] NMin %[[#A]] %[[#B]]
+; CL: %[[#Ord:]] = OpOrdered %[[#Bool]] %[[#A]] %[[#B]]
+; VK: %[[#Ord:]] = OpLogicalNot %[[#Bool]]
+; CHECK: %[[#Res:]] = OpSelect %[[#F32]] %[[#Ord]] %[[#Min]] %[[#NaN32]]
+; CHECK-NEXT: OpReturnValue %[[#Res]]
+define float @minimum_f32_nsz(float %a, float %b) {
+  %r = call nsz float @llvm.minimum.f32(float %a, float %b)
+  ret float %r
+}
+
+; With nnan and nsz, fmin/fmax (NMin/NMax) is enough.
+; CHECK-LABEL: Begin function minimum_f32_nnan_nsz
+; CHECK: %[[#A:]] = OpFunctionParameter %[[#F32]]
+; CHECK: %[[#B:]] = OpFunctionParameter %[[#F32]]
+; CHECK-NEXT: OpLabel
+; CL-NEXT: %[[#Res:]] = OpExtInst %[[#F32]] %[[#Ext]] fmin %[[#A]] %[[#B]]
+; VK-NEXT: %[[#Res:]] = OpExtInst %[[#F32]] %[[#Ext]] NMin %[[#A]] %[[#B]]
+; CHECK-NEXT: OpReturnValue %[[#Res]]
+define float @minimum_f32_nnan_nsz(float %a, float %b) {
+  %r = call nnan nsz float @llvm.minimum.f32(float %a, float %b)
+  ret float %r
+}
+
+; CHECK-LABEL: Begin function maximum_f32_nnan_nsz
+; CHECK: %[[#A:]] = OpFunctionParameter %[[#F32]]
+; CHECK: %[[#B:]] = OpFunctionParameter %[[#F32]]
+; CHECK-NEXT: OpLabel
+; CL-NEXT: %[[#Res:]] = OpExtInst %[[#F32]] %[[#Ext]] fmax %[[#A]] %[[#B]]
+; VK-NEXT: %[[#Res:]] = OpExtInst %[[#F32]] %[[#Ext]] NMax %[[#A]] %[[#B]]
+; CHECK-NEXT: OpReturnValue %[[#Res]]
+define float @maximum_f32_nnan_nsz(float %a, float %b) {
+  %r = call fast float @llvm.maximum.f32(float %a, float %b)
+  ret float %r
+}
+
+; CHECK-LABEL: Begin function minimum_f16
+; CL: %[[#Min:]] = OpExtInst %[[#F16]] %[[#Ext]] fmin
+; VK: %[[#Min:]] = OpExtInst %[[#F16]] %[[#Ext]] NMin
+; CHECK: %[[#NaNSel:]] = OpSelect %[[#F16]] %[[#]] %[[#Min]] %[[#NaN16]]
+; CHECK: %[[#IsZero:]] = OpFOrdEqual %[[#]] %[[#NaNSel]] %[[#]]
+; CHECK: %[[#Res:]] = OpSelect %[[#F16]] %[[#IsZero]] %[[#]] %[[#NaNSel]]
+; CHECK-NEXT: OpReturnValue %[[#Res]]
+define half @minimum_f16(half %a, half %b) {
+  %r = call half @llvm.minimum.f16(half %a, half %b)
+  ret half %r
+}
+
+; CHECK-LABEL: Begin function maximum_f64
+; CL: %[[#Max:]] = OpExtInst %[[#F64]] %[[#Ext]] fmax
+; VK: %[[#Max:]] = OpExtInst %[[#F64]] %[[#Ext]] NMax
+; CHECK: %[[#NaNSel:]] = OpSelect %[[#F64]] %[[#]] %[[#Max]] %[[#NaN64]]
+; CHECK: %[[#IsZero:]] = OpFOrdEqual %[[#]] %[[#NaNSel]] %[[#]]
+; CHECK: %[[#Res:]] = OpSelect %[[#F64]] %[[#IsZero]] %[[#]] %[[#NaNSel]]
+; CHECK-NEXT: OpReturnValue %[[#Res]]
+define double @maximum_f64(double %a, double %b) {
+  %r = call double @llvm.maximum.f64(double %a, double %b)
+  ret double %r
+}
+
+; CHECK-LABEL: Begin function minimum_v2f32
+; CL: %[[#Min:]] = OpExtInst %[[#V2F32]] %[[#Ext]] fmin
+; VK: %[[#Min:]] = OpExtInst %[[#V2F32]] %[[#Ext]] NMin
+; CHECK: %[[#NaNSel:]] = OpSelect %[[#V2F32]] %[[#]] %[[#Min]] %[[#]]
+; CHECK: %[[#IsZero:]] = OpFOrdEqual %[[#]] %[[#NaNSel]] %[[#]]
+; CHECK: %[[#Res:]] = OpSelect %[[#V2F32]] %[[#IsZero]] %[[#]] %[[#NaNSel]]
+; CHECK-NEXT: OpReturnValue %[[#Res]]
+define <2 x float> @minimum_v2f32(<2 x float> %a, <2 x float> %b) {
+  %r = call <2 x float> @llvm.minimum.v2f32(<2 x float> %a, <2 x float> %b)
+  ret <2 x float> %r
+}
+
+; CHECK-LABEL: Begin function maximum_v3f32
+; CL: %[[#Max:]] = OpExtInst %[[#V3F32]] %[[#Ext]] fmax
+; VK: %[[#Max:]] = OpExtInst %[[#V3F32]] %[[#Ext]] NMax
+; CHECK: %[[#NaNSel:]] = OpSelect %[[#V3F32]] %[[#]] %[[#Max]] %[[#]]
+; CHECK: %[[#IsZero:]] = OpFOrdEqual %[[#]] %[[#NaNSel]] %[[#]]
+; CHECK: %[[#Res:]] = OpSelect %[[#V3F32]] %[[#IsZero]] %[[#]] %[[#NaNSel]]
+; CHECK-NEXT: OpReturnValue %[[#Res]]
+define <3 x float> @maximum_v3f32(<3 x float> %a, <3 x float> %b) {
+  %r = call <3 x float> @llvm.maximum.v3f32(<3 x float> %a, <3 x float> %b)
+  ret <3 x float> %r
+}
+
+; CHECK-LABEL: Begin function minimum_v4f32
+; CHECK: %[[#A:]] = OpFunctionParameter %[[#V4F32]]
+; CHECK: %[[#B:]] = OpFunctionParameter %[[#V4F32]]
+; CL: %[[#Min:]] = OpExtInst %[[#V4F32]] %[[#Ext]] fmin %[[#A]] %[[#B]]
+; VK: %[[#Min:]] = OpExtInst %[[#V4F32]] %[[#Ext]] NMin %[[#A]] %[[#B]]
+; CL: %[[#Ord:]] = OpOrdered %[[#V4Bool]] %[[#A]] %[[#B]]
+; VK: %[[#Ord:]] = OpLogicalNot %[[#V4Bool]]
+; CHECK: %[[#NaNSel:]] = OpSelect %[[#V4F32]] %[[#Ord]] %[[#Min]] %[[#]]
+; CHECK: %[[#IsZero:]] = OpFOrdEqual %[[#V4Bool]] %[[#NaNSel]] %[[#]]
+; CHECK: %[[#Res:]] = OpSelect %[[#V4F32]] %[[#IsZero]] %[[#]] %[[#NaNSel]]
+; CHECK-NEXT: OpReturnValue %[[#Res]]
+define <4 x float> @minimum_v4f32(<4 x float> %a, <4 x float> %b) {
+  %r = call <4 x float> @llvm.minimum.v4f32(<4 x float> %a, <4 x float> %b)
+  ret <4 x float> %r
+}
+
+; CHECK-LABEL: Begin function maximum_v4f32_nnan_nsz
+; CHECK: %[[#A:]] = OpFunctionParameter %[[#V4F32]]
+; CHECK: %[[#B:]] = OpFunctionParameter %[[#V4F32]]
+; CHECK-NEXT: OpLabel
+; CL-NEXT: %[[#Res:]] = OpExtInst %[[#V4F32]] %[[#Ext]] fmax %[[#A]] %[[#B]]
+; VK-NEXT: %[[#Res:]] = OpExtInst %[[#V4F32]] %[[#Ext]] NMax %[[#A]] %[[#B]]
+; CHECK-NEXT: OpReturnValue %[[#Res]]
+define <4 x float> @maximum_v4f32_nnan_nsz(<4 x float> %a, <4 x float> %b) {
+  %r = call nnan nsz <4 x float> @llvm.maximum.v4f32(<4 x float> %a, <4 x float> %b)
+  ret <4 x float> %r
+}
diff --git a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/fp-intrinsics.ll b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/fp-intrinsics.ll
index 34116643e2e6df..d2f755be5f1a8e 100644
--- a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/fp-intrinsics.ll
+++ b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/fp-intrinsics.ll
@@ -211,7 +211,11 @@ declare float @llvm.maxnum.f32(float, float)
 ; CHECK: OpFunction
 ; CHECK: %[[#x:]] = OpFunctionParameter %[[#]]
 ; CHECK: %[[#y:]] = OpFunctionParameter %[[#]]
-; CHECK: %[[#res:]] = OpExtInst %[[#]] %[[#]] fmin %[[#x]] %[[#y]]
+; CHECK: %[[#minmax:]] = OpExtInst %[[#var1]] %[[#extinst_id]] fmin %[[#x]] %[[#y]]
+; CHECK: %[[#ord:]] = OpOrdered %[[#]] %[[#x]] %[[#y]]
+; CHECK: %[[#nan:]] = OpSelect %[[#var1]] %[[#ord]] %[[#minmax]] %[[#]]
+; CHECK: %[[#iszero:]] = OpFOrdEqual %[[#]] %[[#nan]] %[[#]]
+; CHECK: %[[#res:]] = OpSelect %[[#var1]] %[[#iszero]] %[[#]] %[[#nan]]
 ; CHECK: OpReturnValue %[[#res]]
 
 define spir_func float @TestMinimum(float %x, float %y) {
@@ -225,7 +229,11 @@ declare float @llvm.minimum.f32(float, float)
 ; CHECK: OpFunction
 ; CHECK: %[[#x:]] = OpFunctionParameter %[[#]]
 ; CHECK: %[[#y:]] = OpFunctionParameter %[[#]]
-; CHECK: %[[#res:]] = OpExtInst %[[#]] %[[#]] fmax %[[#x]] %[[#y]]
+; CHECK: %[[#minmax:]] = OpExtInst %[[#var1]] %[[#extinst_id]] fmax %[[#x]] %[[#y]]
+; CHECK: %[[#ord:]] = OpOrdered %[[#]] %[[#x]] %[[#y]]
+; CHECK: %[[#nan:]] = OpSelect %[[#var1]] %[[#ord]] %[[#minmax]] %[[#]]
+; CHECK: %[[#iszero:]] = OpFOrdEqual %[[#]] %[[#nan]] %[[#]]
+; CHECK: %[[#res:]] = OpSelect %[[#var1]] %[[#iszero]] %[[#]] %[[#nan]]
 ; CHECK: OpReturnValue %[[#res]]
 
 define spir_func float @TestMaximum(float %x, float %y) {
diff --git a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/fmaximum.ll b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/fmaximum.ll
index d28f26cd62aa62..e410e0c3bd0030 100644
--- a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/fmaximum.ll
+++ b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/fmaximum.ll
@@ -18,7 +18,11 @@ target triple = "spir64-unknown-unknown"
 ; CHECK: OpFunction
 ; CHECK: %[[ParamVec2Half:.*]] = OpFunctionParameter %[[HalfVec2]]
 ; CHECK: %[[Vec2HalfShuf:.*]] = OpVectorShuffle %[[HalfVec2]] %[[ParamVec2Half]] %[[#]] 1 0xFFFFFFFF
-; CHECK: %[[Vec2HalfR1:.*]] = OpExtInst %[[HalfVec2]] %[[#]] fmax %[[ParamVec2Half]] %[[Vec2HalfShuf]]
+; CHECK: %[[Vec2HalfR1MinMax:.*]] = OpExtInst %[[HalfVec2]] %[[#]] fmax %[[ParamVec2Half]] %[[Vec2HalfShuf]]
+; CHECK: %[[Vec2HalfR1Ord:.*]] = OpOrdered %[[#]] %[[ParamVec2Half]] %[[Vec2HalfShuf]]
+; CHECK: %[[Vec2HalfR1NaN:.*]] = OpSelect %[[HalfVec2]] %[[Vec2HalfR1Ord]] %[[Vec2HalfR1MinMax]] %[[#]]
+; CHECK: %[[Vec2HalfR1IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec2HalfR1NaN]] %[[#]]
+; CHECK: %[[Vec2HalfR1:.*]] = OpSelect %[[HalfVec2]] %[[Vec2HalfR1IsZero]] %[[#]] %[[Vec2HalfR1NaN]]
 ; CHECK: %[[Vec2HalfR2:.*]] = OpCompositeExtract %[[Half]] %[[Vec2HalfR1]] 0
 ; CHECK: OpReturnValue %[[Vec2HalfR2]]
 ; CHECK: OpFunctionEnd
@@ -28,15 +32,27 @@ target triple = "spir64-unknown-unknown"
 ; CHECK: %[[Vec3HalfItem0:.*]] = OpCompositeExtract %[[Half]] %[[ParamVec3Half]] 0
 ; CHECK: %[[Vec3HalfItem1:.*]] = OpCompositeExtract %[[Half]] %[[ParamVec3Half]] 1
 ; CHECK: %[[Vec3HalfItem2:.*]] = OpCompositeExtract %[[Half]] %[[ParamVec3Half]] 2
-; CHECK: %[[Vec3HalfR1:.*]] = OpExtInst %[[Half]] %[[#]] fmax %[[Vec3HalfItem0]] %[[Vec3HalfItem1]]
-; CHECK: %[[Vec3HalfR2:.*]] = OpExtInst %[[Half]] %[[#]] fmax %[[Vec3HalfR1]] %[[Vec3HalfItem2]]
+; CHECK: %[[Vec3HalfR1MinMax:.*]] = OpExtInst %[[Half]] %[[#]] fmax %[[Vec3HalfItem0]] %[[Vec3HalfItem1]]
+; CHECK: %[[Vec3HalfR1Ord:.*]] = OpOrdered %[[#]] %[[Vec3HalfItem0]] %[[Vec3HalfItem1]]
+; CHECK: %[[Vec3HalfR1NaN:.*]] = OpSelect %[[Half]] %[[Vec3HalfR1Ord]] %[[Vec3HalfR1MinMax]] %[[#]]
+; CHECK: %[[Vec3HalfR1IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec3HalfR1NaN]] %[[#]]
+; CHECK: %[[Vec3HalfR1:.*]] = OpSelect %[[Half]] %[[Vec3HalfR1IsZero]] %[[#]] %[[Vec3HalfR1NaN]]
+; CHECK: %[[Vec3HalfR2MinMax:.*]] = OpExtInst %[[Half]] %[[#]] fmax %[[Vec3HalfR1]] %[[Vec3HalfItem2]]
+; CHECK: %[[Vec3HalfR2Ord:.*]] = OpOrdered %[[#]] %[[Vec3HalfR1]] %[[Vec3HalfItem2]]
+; CHECK: %[[Vec3HalfR2NaN:.*]] = OpSelect %[[Half]] %[[Vec3HalfR2Ord]] %[[Vec3HalfR2MinMax]] %[[#]]
+; CHECK: %[[Vec3HalfR2IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec3HalfR2NaN]] %[[#]]
+; CHECK: %[[Vec3HalfR2:.*]] = OpSelect %[[Half]] %[[Vec3HalfR2IsZero]] %[[#]] %[[Vec3HalfR2NaN]]
 ; CHECK: OpReturnValue %[[Vec3HalfR2]]
 ; CHECK: OpFunctionEnd
 
 ; CHECK: OpFunction
 ; CHECK: %[[ParamVec2Float:.*]] = OpFunctionParameter %[[FloatVec2]]
 ; CHECK: %[[Vec2FloatShuf:.*]] = OpVectorShuffle %[[FloatVec2]] %[[ParamVec2Float]] %[[#]] 1 0xFFFFFFFF
-; CHECK: %[[Vec2FloatR1:.*]] = OpExtInst %[[FloatVec2]] %[[#]] fmax %[[ParamVec2Float]] %[[Vec2FloatShuf]]
+; CHECK: %[[Vec2FloatR1MinMax:.*]] = OpExtInst %[[FloatVec2]] %[[#]] fmax %[[ParamVec2Float]] %[[Vec2FloatShuf]]
+; CHECK: %[[Vec2FloatR1Ord:.*]] = OpOrdered %[[#]] %[[ParamVec2Float]] %[[Vec2FloatShuf]]
+; CHECK: %[[Vec2FloatR1NaN:.*]] = OpSelect %[[FloatVec2]] %[[Vec2FloatR1Ord]] %[[Vec2FloatR1MinMax]] %[[#]]
+; CHECK: %[[Vec2FloatR1IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec2FloatR1NaN]] %[[#]]
+; CHECK: %[[Vec2FloatR1:.*]] = OpSelect %[[FloatVec2]] %[[Vec2FloatR1IsZero]] %[[#]] %[[Vec2FloatR1NaN]]
 ; CHECK: %[[Vec2FloatR2:.*]] = OpCompositeExtract %[[Float]] %[[Vec2FloatR1]] 0
 ; CHECK: OpReturnValue %[[Vec2FloatR2]]
 ; CHECK: OpFunctionEnd
@@ -46,15 +62,27 @@ target triple = "spir64-unknown-unknown"
 ; CHECK: %[[Vec3FloatItem0:.*]] = OpCompositeExtract %[[Float]] %[[ParamVec3Float]] 0
 ; CHECK: %[[Vec3FloatItem1:.*]] = OpCompositeExtract %[[Float]] %[[ParamVec3Float]] 1
 ; CHECK: %[[Vec3FloatItem2:.*]] = OpCompositeExtract %[[Float]] %[[ParamVec3Float]] 2
-; CHECK: %[[Vec3FloatR1:.*]] = OpExtInst %[[Float]] %[[#]] fmax %[[Vec3FloatItem0]] %[[Vec3FloatItem1]]
-; CHECK: %[[Vec3FloatR2:.*]] = OpExtInst %[[Float]] %[[#]] fmax %[[Vec3FloatR1]] %[[Vec3FloatItem2]]
+; CHECK: %[[Vec3FloatR1MinMax:.*]] = OpExtInst %[[Float]] %[[#]] fmax %[[Vec3FloatItem0]] %[[Vec3FloatItem1]]
+; CHECK: %[[Vec3FloatR1Ord:.*]] = OpOrdered %[[#]] %[[Vec3FloatItem0]] %[[Vec3FloatItem1]]
+; CHECK: %[[Vec3FloatR1NaN:.*]] = OpSelect %[[Float]] %[[Vec3FloatR1Ord]] %[[Vec3FloatR1MinMax]] %[[#]]
+; CHECK: %[[Vec3FloatR1IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec3FloatR1NaN]] %[[#]]
+; CHECK: %[[Vec3FloatR1:.*]] = OpSelect %[[Float]] %[[Vec3FloatR1IsZero]] %[[#]] %[[Vec3FloatR1NaN]]
+; CHECK: %[[Vec3FloatR2MinMax:.*]] = OpExtInst %[[Float]] %[[#]] fmax %[[Vec3FloatR1]] %[[Vec3FloatItem2]]
+; CHECK: %[[Vec3FloatR2Ord:.*]] = OpOrdered %[[#]] %[[Vec3FloatR1]] %[[Vec3FloatItem2]]
+; CHECK: %[[Vec3FloatR2NaN:.*]] = OpSelect %[[Float]] %[[Vec3FloatR2Ord]] %[[Vec3FloatR2MinMax]] %[[#]]
+; CHECK: %[[Vec3FloatR2IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec3FloatR2NaN]] %[[#]]
+; CHECK: %[[Vec3FloatR2:.*]] = OpSelect %[[Float]] %[[Vec3FloatR2IsZero]] %[[#]] %[[Vec3FloatR2NaN]]
 ; CHECK: OpReturnValue %[[Vec3FloatR2]]
 ; CHECK: OpFunctionEnd
 
 ; CHECK: OpFunction
 ; CHECK: %[[ParamVec2Double:.*]] = OpFunctionParameter %[[DoubleVec2]]
 ; CHECK: %[[Vec2DoubleShuf:.*]] = OpVectorShuffle %[[DoubleVec2]] %[[ParamVec2Double]] %[[#]] 1 0xFFFFFFFF
-; CHECK: %[[Vec2DoubleR1:.*]] = OpExtInst %[[DoubleVec2]] %[[#]] fmax %[[ParamVec2Double]] %[[Vec2DoubleShuf]]
+; CHECK: %[[Vec2DoubleR1MinMax:.*]] = OpExtInst %[[DoubleVec2]] %[[#]] fmax %[[ParamVec2Double]] %[[Vec2DoubleShuf]]
+; CHECK: %[[Vec2DoubleR1Ord:.*]] = OpOrdered %[[#]] %[[ParamVec2Double]] %[[Vec2DoubleShuf]]
+; CHECK: %[[Vec2DoubleR1NaN:.*]] = OpSelect %[[DoubleVec2]] %[[Vec2DoubleR1Ord]] %[[Vec2DoubleR1MinMax]] %[[#]]
+; CHECK: %[[Vec2DoubleR1IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec2DoubleR1NaN]] %[[#]]
+; CHECK: %[[Vec2DoubleR1:.*]] = OpSelect %[[DoubleVec2]] %[[Vec2DoubleR1IsZero]] %[[#]] %[[Vec2DoubleR1NaN]]
 ; CHECK: %[[Vec2DoubleR2:.*]] = OpCompositeExtract %[[Double]] %[[Vec2DoubleR1]] 0
 ; CHECK: OpReturnValue %[[Vec2DoubleR2]]
 ; CHECK: OpFunctionEnd
@@ -64,8 +92,16 @@ target triple = "spir64-unknown-unknown"
 ; CHECK: %[[Vec3DoubleItem0:.*]] = OpCompositeExtract %[[Double]] %[[ParamVec3Double]] 0
 ; CHECK: %[[Vec3DoubleItem1:.*]] = OpCompositeExtract %[[Double]] %[[ParamVec3Double]] 1
 ; CHECK: %[[Vec3DoubleItem2:.*]] = OpCompositeExtract %[[Double]] %[[ParamVec3Double]] 2
-; CHECK: %[[Vec3DoubleR1:.*]] = OpExtInst %[[Double]] %[[#]] fmax %[[Vec3DoubleItem0]] %[[Vec3DoubleItem1]]
-; CHECK: %[[Vec3DoubleR2:.*]] = OpExtInst %[[Double]] %[[#]] fmax %[[Vec3DoubleR1]] %[[Vec3DoubleItem2]]
+; CHECK: %[[Vec3DoubleR1MinMax:.*]] = OpExtInst %[[Double]] %[[#]] fmax %[[Vec3DoubleItem0]] %[[Vec3DoubleItem1]]
+; CHECK: %[[Vec3DoubleR1Ord:.*]] = OpOrdered %[[#]] %[[Vec3DoubleItem0]] %[[Vec3DoubleItem1]]
+; CHECK: %[[Vec3DoubleR1NaN:.*]] = OpSelect %[[Double]] %[[Vec3DoubleR1Ord]] %[[Vec3DoubleR1MinMax]] %[[#]]
+; CHECK: %[[Vec3DoubleR1IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec3DoubleR1NaN]] %[[#]]
+; CHECK: %[[Vec3DoubleR1:.*]] = OpSelect %[[Double]] %[[Vec3DoubleR1IsZero]] %[[#]] %[[Vec3DoubleR1NaN]]
+; CHECK: %[[Vec3DoubleR2MinMax:.*]] = OpExtInst %[[Double]] %[[#]] fmax %[[Vec3DoubleR1]] %[[Vec3DoubleItem2]]
+; CHECK: %[[Vec3DoubleR2Ord:.*]] = OpOrdered %[[#]] %[[Vec3DoubleR1]] %[[Vec3DoubleItem2]]
+; CHECK: %[[Vec3DoubleR2NaN:.*]] = OpSelect %[[Double]] %[[Vec3DoubleR2Ord]] %[[Vec3DoubleR2MinMax]] %[[#]]
+; CHECK: %[[Vec3DoubleR2IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec3DoubleR2NaN]] %[[#]]
+; CHECK: %[[Vec3DoubleR2:.*]] = OpSelect %[[Double]] %[[Vec3DoubleR2IsZero]] %[[#]] %[[Vec3DoubleR2NaN]]
 ; CHECK: OpReturnValue %[[Vec3DoubleR2]]
 ; CHECK: OpFunctionEnd
 
diff --git a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/fminimum.ll b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/fminimum.ll
index 53ef537ac3385d..a85a24b66a32fc 100644
--- a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/fminimum.ll
+++ b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/llvm-vector-reduce/fminimum.ll
@@ -18,7 +18,11 @@ target triple = "spir64-unknown-unknown"
 ; CHECK: OpFunction
 ; CHECK: %[[ParamVec2Half:.*]] = OpFunctionParameter %[[HalfVec2]]
 ; CHECK: %[[Vec2HalfShuf:.*]] = OpVectorShuffle %[[HalfVec2]] %[[ParamVec2Half]] %[[#]] 1 0xFFFFFFFF
-; CHECK: %[[Vec2HalfR1:.*]] = OpExtInst %[[HalfVec2]] %[[#]] fmin %[[ParamVec2Half]] %[[Vec2HalfShuf]]
+; CHECK: %[[Vec2HalfR1MinMax:.*]] = OpExtInst %[[HalfVec2]] %[[#]] fmin %[[ParamVec2Half]] %[[Vec2HalfShuf]]
+; CHECK: %[[Vec2HalfR1Ord:.*]] = OpOrdered %[[#]] %[[ParamVec2Half]] %[[Vec2HalfShuf]]
+; CHECK: %[[Vec2HalfR1NaN:.*]] = OpSelect %[[HalfVec2]] %[[Vec2HalfR1Ord]] %[[Vec2HalfR1MinMax]] %[[#]]
+; CHECK: %[[Vec2HalfR1IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec2HalfR1NaN]] %[[#]]
+; CHECK: %[[Vec2HalfR1:.*]] = OpSelect %[[HalfVec2]] %[[Vec2HalfR1IsZero]] %[[#]] %[[Vec2HalfR1NaN]]
 ; CHECK: %[[Vec2HalfR2:.*]] = OpCompositeExtract %[[Half]] %[[Vec2HalfR1]] 0
 ; CHECK: OpReturnValue %[[Vec2HalfR2]]
 ; CHECK: OpFunctionEnd
@@ -28,15 +32,27 @@ target triple = "spir64-unknown-unknown"
 ; CHECK: %[[Vec3HalfItem0:.*]] = OpCompositeExtract %[[Half]] %[[ParamVec3Half]] 0
 ; CHECK: %[[Vec3HalfItem1:.*]] = OpCompositeExtract %[[Half]] %[[ParamVec3Half]] 1
 ; CHECK: %[[Vec3HalfItem2:.*]] = OpCompositeExtract %[[Half]] %[[ParamVec3Half]] 2
-; CHECK: %[[Vec3HalfR1:.*]] = OpExtInst %[[Half]] %[[#]] fmin %[[Vec3HalfItem0]] %[[Vec3HalfItem1]]
-; CHECK: %[[Vec3HalfR2:.*]] = OpExtInst %[[Half]] %[[#]] fmin %[[Vec3HalfR1]] %[[Vec3HalfItem2]]
+; CHECK: %[[Vec3HalfR1MinMax:.*]] = OpExtInst %[[Half]] %[[#]] fmin %[[Vec3HalfItem0]] %[[Vec3HalfItem1]]
+; CHECK: %[[Vec3HalfR1Ord:.*]] = OpOrdered %[[#]] %[[Vec3HalfItem0]] %[[Vec3HalfItem1]]
+; CHECK: %[[Vec3HalfR1NaN:.*]] = OpSelect %[[Half]] %[[Vec3HalfR1Ord]] %[[Vec3HalfR1MinMax]] %[[#]]
+; CHECK: %[[Vec3HalfR1IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec3HalfR1NaN]] %[[#]]
+; CHECK: %[[Vec3HalfR1:.*]] = OpSelect %[[Half]] %[[Vec3HalfR1IsZero]] %[[#]] %[[Vec3HalfR1NaN]]
+; CHECK: %[[Vec3HalfR2MinMax:.*]] = OpExtInst %[[Half]] %[[#]] fmin %[[Vec3HalfR1]] %[[Vec3HalfItem2]]
+; CHECK: %[[Vec3HalfR2Ord:.*]] = OpOrdered %[[#]] %[[Vec3HalfR1]] %[[Vec3HalfItem2]]
+; CHECK: %[[Vec3HalfR2NaN:.*]] = OpSelect %[[Half]] %[[Vec3HalfR2Ord]] %[[Vec3HalfR2MinMax]] %[[#]]
+; CHECK: %[[Vec3HalfR2IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec3HalfR2NaN]] %[[#]]
+; CHECK: %[[Vec3HalfR2:.*]] = OpSelect %[[Half]] %[[Vec3HalfR2IsZero]] %[[#]] %[[Vec3HalfR2NaN]]
 ; CHECK: OpReturnValue %[[Vec3HalfR2]]
 ; CHECK: OpFunctionEnd
 
 ; CHECK: OpFunction
 ; CHECK: %[[ParamVec2Float:.*]] = OpFunctionParameter %[[FloatVec2]]
 ; CHECK: %[[Vec2FloatShuf:.*]] = OpVectorShuffle %[[FloatVec2]] %[[ParamVec2Float]] %[[#]] 1 0xFFFFFFFF
-; CHECK: %[[Vec2FloatR1:.*]] = OpExtInst %[[FloatVec2]] %[[#]] fmin %[[ParamVec2Float]] %[[Vec2FloatShuf]]
+; CHECK: %[[Vec2FloatR1MinMax:.*]] = OpExtInst %[[FloatVec2]] %[[#]] fmin %[[ParamVec2Float]] %[[Vec2FloatShuf]]
+; CHECK: %[[Vec2FloatR1Ord:.*]] = OpOrdered %[[#]] %[[ParamVec2Float]] %[[Vec2FloatShuf]]
+; CHECK: %[[Vec2FloatR1NaN:.*]] = OpSelect %[[FloatVec2]] %[[Vec2FloatR1Ord]] %[[Vec2FloatR1MinMax]] %[[#]]
+; CHECK: %[[Vec2FloatR1IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec2FloatR1NaN]] %[[#]]
+; CHECK: %[[Vec2FloatR1:.*]] = OpSelect %[[FloatVec2]] %[[Vec2FloatR1IsZero]] %[[#]] %[[Vec2FloatR1NaN]]
 ; CHECK: %[[Vec2FloatR2:.*]] = OpCompositeExtract %[[Float]] %[[Vec2FloatR1]] 0
 ; CHECK: OpReturnValue %[[Vec2FloatR2]]
 ; CHECK: OpFunctionEnd
@@ -46,15 +62,27 @@ target triple = "spir64-unknown-unknown"
 ; CHECK: %[[Vec3FloatItem0:.*]] = OpCompositeExtract %[[Float]] %[[ParamVec3Float]] 0
 ; CHECK: %[[Vec3FloatItem1:.*]] = OpCompositeExtract %[[Float]] %[[ParamVec3Float]] 1
 ; CHECK: %[[Vec3FloatItem2:.*]] = OpCompositeExtract %[[Float]] %[[ParamVec3Float]] 2
-; CHECK: %[[Vec3FloatR1:.*]] = OpExtInst %[[Float]] %[[#]] fmin %[[Vec3FloatItem0]] %[[Vec3FloatItem1]]
-; CHECK: %[[Vec3FloatR2:.*]] = OpExtInst %[[Float]] %[[#]] fmin %[[Vec3FloatR1]] %[[Vec3FloatItem2]]
+; CHECK: %[[Vec3FloatR1MinMax:.*]] = OpExtInst %[[Float]] %[[#]] fmin %[[Vec3FloatItem0]] %[[Vec3FloatItem1]]
+; CHECK: %[[Vec3FloatR1Ord:.*]] = OpOrdered %[[#]] %[[Vec3FloatItem0]] %[[Vec3FloatItem1]]
+; CHECK: %[[Vec3FloatR1NaN:.*]] = OpSelect %[[Float]] %[[Vec3FloatR1Ord]] %[[Vec3FloatR1MinMax]] %[[#]]
+; CHECK: %[[Vec3FloatR1IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec3FloatR1NaN]] %[[#]]
+; CHECK: %[[Vec3FloatR1:.*]] = OpSelect %[[Float]] %[[Vec3FloatR1IsZero]] %[[#]] %[[Vec3FloatR1NaN]]
+; CHECK: %[[Vec3FloatR2MinMax:.*]] = OpExtInst %[[Float]] %[[#]] fmin %[[Vec3FloatR1]] %[[Vec3FloatItem2]]
+; CHECK: %[[Vec3FloatR2Ord:.*]] = OpOrdered %[[#]] %[[Vec3FloatR1]] %[[Vec3FloatItem2]]
+; CHECK: %[[Vec3FloatR2NaN:.*]] = OpSelect %[[Float]] %[[Vec3FloatR2Ord]] %[[Vec3FloatR2MinMax]] %[[#]]
+; CHECK: %[[Vec3FloatR2IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec3FloatR2NaN]] %[[#]]
+; CHECK: %[[Vec3FloatR2:.*]] = OpSelect %[[Float]] %[[Vec3FloatR2IsZero]] %[[#]] %[[Vec3FloatR2NaN]]
 ; CHECK: OpReturnValue %[[Vec3FloatR2]]
 ; CHECK: OpFunctionEnd
 
 ; CHECK: OpFunction
 ; CHECK: %[[ParamVec2Double:.*]] = OpFunctionParameter %[[DoubleVec2]]
 ; CHECK: %[[Vec2DoubleShuf:.*]] = OpVectorShuffle %[[DoubleVec2]] %[[ParamVec2Double]] %[[#]] 1 0xFFFFFFFF
-; CHECK: %[[Vec2DoubleR1:.*]] = OpExtInst %[[DoubleVec2]] %[[#]] fmin %[[ParamVec2Double]] %[[Vec2DoubleShuf]]
+; CHECK: %[[Vec2DoubleR1MinMax:.*]] = OpExtInst %[[DoubleVec2]] %[[#]] fmin %[[ParamVec2Double]] %[[Vec2DoubleShuf]]
+; CHECK: %[[Vec2DoubleR1Ord:.*]] = OpOrdered %[[#]] %[[ParamVec2Double]] %[[Vec2DoubleShuf]]
+; CHECK: %[[Vec2DoubleR1NaN:.*]] = OpSelect %[[DoubleVec2]] %[[Vec2DoubleR1Ord]] %[[Vec2DoubleR1MinMax]] %[[#]]
+; CHECK: %[[Vec2DoubleR1IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec2DoubleR1NaN]] %[[#]]
+; CHECK: %[[Vec2DoubleR1:.*]] = OpSelect %[[DoubleVec2]] %[[Vec2DoubleR1IsZero]] %[[#]] %[[Vec2DoubleR1NaN]]
 ; CHECK: %[[Vec2DoubleR2:.*]] = OpCompositeExtract %[[Double]] %[[Vec2DoubleR1]] 0
 ; CHECK: OpReturnValue %[[Vec2DoubleR2]]
 ; CHECK: OpFunctionEnd
@@ -64,8 +92,16 @@ target triple = "spir64-unknown-unknown"
 ; CHECK: %[[Vec3DoubleItem0:.*]] = OpCompositeExtract %[[Double]] %[[ParamVec3Double]] 0
 ; CHECK: %[[Vec3DoubleItem1:.*]] = OpCompositeExtract %[[Double]] %[[ParamVec3Double]] 1
 ; CHECK: %[[Vec3DoubleItem2:.*]] = OpCompositeExtract %[[Double]] %[[ParamVec3Double]] 2
-; CHECK: %[[Vec3DoubleR1:.*]] = OpExtInst %[[Double]] %[[#]] fmin %[[Vec3DoubleItem0]] %[[Vec3DoubleItem1]]
-; CHECK: %[[Vec3DoubleR2:.*]] = OpExtInst %[[Double]] %[[#]] fmin %[[Vec3DoubleR1]] %[[Vec3DoubleItem2]]
+; CHECK: %[[Vec3DoubleR1MinMax:.*]] = OpExtInst %[[Double]] %[[#]] fmin %[[Vec3DoubleItem0]] %[[Vec3DoubleItem1]]
+; CHECK: %[[Vec3DoubleR1Ord:.*]] = OpOrdered %[[#]] %[[Vec3DoubleItem0]] %[[Vec3DoubleItem1]]
+; CHECK: %[[Vec3DoubleR1NaN:.*]] = OpSelect %[[Double]] %[[Vec3DoubleR1Ord]] %[[Vec3DoubleR1MinMax]] %[[#]]
+; CHECK: %[[Vec3DoubleR1IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec3DoubleR1NaN]] %[[#]]
+; CHECK: %[[Vec3DoubleR1:.*]] = OpSelect %[[Double]] %[[Vec3DoubleR1IsZero]] %[[#]] %[[Vec3DoubleR1NaN]]
+; CHECK: %[[Vec3DoubleR2MinMax:.*]] = OpExtInst %[[Double]] %[[#]] fmin %[[Vec3DoubleR1]] %[[Vec3DoubleItem2]]
+; CHECK: %[[Vec3DoubleR2Ord:.*]] = OpOrdered %[[#]] %[[Vec3DoubleR1]] %[[Vec3DoubleItem2]]
+; CHECK: %[[Vec3DoubleR2NaN:.*]] = OpSelect %[[Double]] %[[Vec3DoubleR2Ord]] %[[Vec3DoubleR2MinMax]] %[[#]]
+; CHECK: %[[Vec3DoubleR2IsZero:.*]] = OpFOrdEqual %[[#]] %[[Vec3DoubleR2NaN]] %[[#]]
+; CHECK: %[[Vec3DoubleR2:.*]] = OpSelect %[[Double]] %[[Vec3DoubleR2IsZero]] %[[#]] %[[Vec3DoubleR2NaN]]
 ; CHECK: OpReturnValue %[[Vec3DoubleR2]]
 ; CHECK: OpFunctionEnd
 



More information about the llvm-commits mailing list