[llvm] [InstCombine] Transform (fcmp + fadd + sel) into (fcmp + sel + fadd) (PR #106492)

Rajat Bajpai via llvm-commits llvm-commits at lists.llvm.org
Fri Oct 4 00:56:01 PDT 2024


https://github.com/rajatbajpai updated https://github.com/llvm/llvm-project/pull/106492

>From 83e129e4ec496a89f8513fdba772b299594fcf9f Mon Sep 17 00:00:00 2001
From: rbajpai <rbajpai at nvidia.com>
Date: Wed, 21 Aug 2024 14:48:08 +0530
Subject: [PATCH 1/5] [InstCombine] Transform (fcmp + fadd + sel) into (fcmp +
 sel + fadd)

Transform `fcmp + fadd + sel` into `fcmp + sel + fadd` which enables
the possibility of lowering `fcmp + sel` into `fmax/fmin`.
---
 .../InstCombine/InstCombineSelect.cpp         |  49 ++++
 .../InstCombine/fcmp-fadd-select.ll           | 245 ++++++++++++++++++
 2 files changed, 294 insertions(+)
 create mode 100644 llvm/test/Transforms/InstCombine/fcmp-fadd-select.ll

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 3f780285efe423..d22d13aec356b8 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -3699,6 +3699,51 @@ static bool hasAffectedValue(Value *V, SmallPtrSetImpl<Value *> &Affected,
   return false;
 }
 
+static Value *foldSelectAddConstant(SelectInst &SI,
+                                    InstCombiner::BuilderTy &Builder) {
+  Value *Cmp;
+  Instruction *FAdd;
+  ConstantFP *C;
+
+  // select((fcmp OGT/OLT, X, 0), (fadd X, C), C) => fadd((select (fcmp OGT/OLT,
+  // X, 0), X, 0), C)
+
+  // This transformation enables the possibility of transforming fcmp + sel into
+  // a fmax/fmin.
+
+  // OneUse check for `Cmp` is necessary because it makes sure that other
+  // InstCombine folds don't undo this transformation and cause an infinite
+  // loop.
+  if (match(&SI, m_Select(m_OneUse(m_Value(Cmp)), m_OneUse(m_Instruction(FAdd)),
+                          m_ConstantFP(C))) ||
+      match(&SI, m_Select(m_OneUse(m_Value(Cmp)), m_ConstantFP(C),
+                          m_OneUse(m_Instruction(FAdd))))) {
+    Value *X;
+    CmpInst::Predicate Pred;
+    if (!match(Cmp, m_FCmp(Pred, m_Value(X), m_AnyZeroFP())))
+      return nullptr;
+
+    if (Pred != CmpInst::FCMP_OGT && Pred != CmpInst::FCMP_OLT)
+      return nullptr;
+
+    if (!match(FAdd, m_FAdd(m_Specific(X), m_Specific(C))))
+      return nullptr;
+
+    FastMathFlags FMF = FAdd->getFastMathFlags();
+    FMF |= SI.getFastMathFlags();
+
+    Value *NewSelect = Builder.CreateSelect(
+        Cmp, X, ConstantFP::getZero(C->getType()), SI.getName() + ".new", &SI);
+    cast<Instruction>(NewSelect)->setFastMathFlags(FMF);
+
+    Value *NewFAdd =
+        Builder.CreateFAddFMF(NewSelect, C, FAdd, FAdd->getName() + ".new");
+    return NewFAdd;
+  }
+
+  return nullptr;
+}
+
 Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
   Value *CondVal = SI.getCondition();
   Value *TrueVal = SI.getTrueValue();
@@ -4095,6 +4140,10 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
   if (Value *V = foldRoundUpIntegerWithPow2Alignment(SI, Builder))
     return replaceInstUsesWith(SI, V);
 
+  if (Value *V = foldSelectAddConstant(SI, Builder)) {
+    return replaceInstUsesWith(SI, V);
+  }
+
   // select(mask, mload(,,mask,0), 0) -> mload(,,mask,0)
   // Load inst is intentionally not checked for hasOneUse()
   if (match(FalseVal, m_Zero()) &&
diff --git a/llvm/test/Transforms/InstCombine/fcmp-fadd-select.ll b/llvm/test/Transforms/InstCombine/fcmp-fadd-select.ll
new file mode 100644
index 00000000000000..fced2d961b2415
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/fcmp-fadd-select.ll
@@ -0,0 +1,245 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+; Check for fcmp + sel pattern which later lowered into fmax
+define float @test_fmax_pos1(float %in) {
+; CHECK-LABEL: define float @test_fmax_pos1(
+; CHECK-SAME: float [[IN:%.*]]) {
+; CHECK-NEXT:    [[CMP1:%.*]] = fcmp ogt float [[IN]], 0.000000e+00
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = select i1 [[CMP1]], float [[IN]], float 0.000000e+00
+; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 1.000000e+00
+; CHECK-NEXT:    ret float [[ADD_NEW]]
+;
+  %cmp1 = fcmp ogt float %in, 0.000000e+00
+  %add = fadd float %in, 1.000000e+00
+  %sel = select i1 %cmp1, float %add, float 1.000000e+00
+  ret float %sel
+}
+
+define float @test_fmax_pos2(float %in) {
+; CHECK-LABEL: define float @test_fmax_pos2(
+; CHECK-SAME: float [[IN:%.*]]) {
+; CHECK-NEXT:    [[CMP1:%.*]] = fcmp ogt float [[IN]], 0.000000e+00
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = select i1 [[CMP1]], float [[IN]], float 0.000000e+00
+; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 1.000000e+00
+; CHECK-NEXT:    ret float [[ADD_NEW]]
+;
+  %cmp1 = fcmp ogt float %in, 0.000000e+00
+  %add = fadd float %in, 1.000000e+00
+  %sel = select i1 %cmp1, float 1.000000e+00, float %add
+  ret float %sel
+}
+
+define float @test_fmax_pos3(float %in) {
+; CHECK-LABEL: define float @test_fmax_pos3(
+; CHECK-SAME: float [[IN:%.*]]) {
+; CHECK-NEXT:    [[CMP1:%.*]] = fcmp ogt float [[IN]], 0.000000e+00
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = select i1 [[CMP1]], float [[IN]], float 0.000000e+00
+; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 1.000000e+00
+; CHECK-NEXT:    ret float [[ADD_NEW]]
+;
+  %cmp1 = fcmp ogt float %in, 0.000000e+00
+  %add = fadd float 1.000000e+00, %in
+  %sel = select i1 %cmp1, float %add, float 1.000000e+00
+  ret float %sel
+}
+
+define float @test_fmax_pos4(float %in) {
+; CHECK-LABEL: define float @test_fmax_pos4(
+; CHECK-SAME: float [[IN:%.*]]) {
+; CHECK-NEXT:    [[CMP1:%.*]] = fcmp ogt float [[IN]], 0.000000e+00
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = select i1 [[CMP1]], float [[IN]], float 0.000000e+00
+; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 1.000000e+00
+; CHECK-NEXT:    ret float [[ADD_NEW]]
+;
+  %cmp1 = fcmp ogt float %in, 0.000000e+00
+  %add = fadd float 1.000000e+00, %in
+  %sel = select i1 %cmp1, float 1.000000e+00, float %add
+  ret float %sel
+}
+
+define float @test_fmax_pos5(float %in) {
+; CHECK-LABEL: define float @test_fmax_pos5(
+; CHECK-SAME: float [[IN:%.*]]) {
+; CHECK-NEXT:    [[CMP1:%.*]] = fcmp ogt float [[IN]], 0.000000e+00
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = select i1 [[CMP1]], float [[IN]], float 0.000000e+00
+; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 2.000000e+00
+; CHECK-NEXT:    ret float [[ADD_NEW]]
+;
+  %cmp1 = fcmp ogt float %in, 0.000000e+00
+  %add = fadd float 2.000000e+00, %in
+  %sel = select i1 %cmp1, float 2.000000e+00, float %add
+  ret float %sel
+}
+
+
+; Check for fcmp + sel pattern which later lowered into fmin
+define float @test_fmin_pos1(float %in) {
+; CHECK-LABEL: define float @test_fmin_pos1(
+; CHECK-SAME: float [[IN:%.*]]) {
+; CHECK-NEXT:    [[CMP1:%.*]] = fcmp olt float [[IN]], 0.000000e+00
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = select i1 [[CMP1]], float [[IN]], float 0.000000e+00
+; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 1.000000e+00
+; CHECK-NEXT:    ret float [[ADD_NEW]]
+;
+  %cmp1 = fcmp olt float %in, 0.000000e+00
+  %add = fadd float %in, 1.000000e+00
+  %sel = select i1 %cmp1, float %add, float 1.000000e+00
+  ret float %sel
+}
+
+define float @test_fmin_pos2(float %in) {
+; CHECK-LABEL: define float @test_fmin_pos2(
+; CHECK-SAME: float [[IN:%.*]]) {
+; CHECK-NEXT:    [[CMP1:%.*]] = fcmp olt float [[IN]], 0.000000e+00
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = select i1 [[CMP1]], float [[IN]], float 0.000000e+00
+; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 1.000000e+00
+; CHECK-NEXT:    ret float [[ADD_NEW]]
+;
+  %cmp1 = fcmp olt float %in, 0.000000e+00
+  %add = fadd float %in, 1.000000e+00
+  %sel = select i1 %cmp1, float 1.000000e+00, float %add
+  ret float %sel
+}
+
+define float @test_fmin_pos3(float %in) {
+; CHECK-LABEL: define float @test_fmin_pos3(
+; CHECK-SAME: float [[IN:%.*]]) {
+; CHECK-NEXT:    [[CMP1:%.*]] = fcmp olt float [[IN]], 0.000000e+00
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = select i1 [[CMP1]], float [[IN]], float 0.000000e+00
+; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 1.000000e+00
+; CHECK-NEXT:    ret float [[ADD_NEW]]
+;
+  %cmp1 = fcmp olt float %in, 0.000000e+00
+  %add = fadd float 1.000000e+00, %in
+  %sel = select i1 %cmp1, float %add, float 1.000000e+00
+  ret float %sel
+}
+
+define float @test_fmin_pos4(float %in) {
+; CHECK-LABEL: define float @test_fmin_pos4(
+; CHECK-SAME: float [[IN:%.*]]) {
+; CHECK-NEXT:    [[CMP1:%.*]] = fcmp olt float [[IN]], 0.000000e+00
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = select i1 [[CMP1]], float [[IN]], float 0.000000e+00
+; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 1.000000e+00
+; CHECK-NEXT:    ret float [[ADD_NEW]]
+;
+  %cmp1 = fcmp olt float %in, 0.000000e+00
+  %add = fadd float 1.000000e+00, %in
+  %sel = select i1 %cmp1, float 1.000000e+00, float %add
+  ret float %sel
+}
+
+define float @test_fmin_pos5(float %in) {
+; CHECK-LABEL: define float @test_fmin_pos5(
+; CHECK-SAME: float [[IN:%.*]]) {
+; CHECK-NEXT:    [[CMP1:%.*]] = fcmp olt float [[IN]], 0.000000e+00
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = select i1 [[CMP1]], float [[IN]], float 0.000000e+00
+; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 2.000000e+00
+; CHECK-NEXT:    ret float [[ADD_NEW]]
+;
+  %cmp1 = fcmp olt float %in, 0.000000e+00
+  %add = fadd float 2.000000e+00, %in
+  %sel = select i1 %cmp1, float 2.000000e+00, float %add
+  ret float %sel
+}
+
+
+; Check for fmax scenarios that shouldn't be transformed.
+define float @test_fmax_neg1(float %in, float %in2) {
+; CHECK-LABEL: define float @test_fmax_neg1(
+; CHECK-SAME: float [[IN:%.*]], float [[IN2:%.*]]) {
+; CHECK-NEXT:    [[CMP1:%.*]] = fcmp ogt float [[IN2]], 0.000000e+00
+; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[IN]], 1.000000e+00
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP1]], float [[ADD]], float 1.000000e+00
+; CHECK-NEXT:    ret float [[SEL]]
+;
+  %cmp1 = fcmp ogt float %in2, 0.000000e+00
+  %add = fadd float %in, 1.000000e+00
+  %sel = select i1 %cmp1, float %add, float 1.000000e+00
+  ret float %sel
+}
+
+define float @test_fmax_neg2(float %in) {
+; CHECK-LABEL: define float @test_fmax_neg2(
+; CHECK-SAME: float [[IN:%.*]]) {
+; CHECK-NEXT:    [[CMP1:%.*]] = fcmp ogt float [[IN]], 1.000000e+00
+; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[IN]], 1.000000e+00
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP1]], float [[ADD]], float 1.000000e+00
+; CHECK-NEXT:    ret float [[SEL]]
+;
+  %cmp1 = fcmp ogt float %in, 1.000000e+00
+  %add = fadd float %in, 1.000000e+00
+  %sel = select i1 %cmp1, float %add, float 1.000000e+00
+  ret float %sel
+}
+
+define float @test_fmax_neg3(float %in) {
+; CHECK-LABEL: define float @test_fmax_neg3(
+; CHECK-SAME: float [[IN:%.*]]) {
+; CHECK-NEXT:    [[CMP1:%.*]] = fcmp ogt float [[IN]], 0.000000e+00
+; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[IN]], 1.000000e+00
+; CHECK-NEXT:    [[ADD_2:%.*]] = fadd float [[IN]], 1.000000e+00
+; CHECK-NEXT:    [[SEL_1:%.*]] = select i1 [[CMP1]], float [[ADD]], float 1.000000e+00
+; CHECK-NEXT:    [[SEL_2:%.*]] = select i1 [[CMP1]], float 2.000000e+00, float [[ADD_2]]
+; CHECK-NEXT:    [[RES:%.*]] = fadd float [[SEL_1]], [[SEL_2]]
+; CHECK-NEXT:    ret float [[RES]]
+;
+  %cmp1 = fcmp ogt float %in, 0.000000e+00
+  %add = fadd float %in, 1.000000e+00
+  %add.2 = fadd float %in, 1.000000e+00
+  %sel.1 = select i1 %cmp1, float %add, float 1.000000e+00
+  %sel.2 = select i1 %cmp1, float 2.000000e+00, float %add.2
+  %res = fadd float %sel.1, %sel.2
+  ret float %res
+}
+
+
+; Check for fmin scenarios that shouldn't be transformed.
+define float @test_fmin_neg1(float %in, float %in2) {
+; CHECK-LABEL: define float @test_fmin_neg1(
+; CHECK-SAME: float [[IN:%.*]], float [[IN2:%.*]]) {
+; CHECK-NEXT:    [[CMP1:%.*]] = fcmp olt float [[IN2]], 0.000000e+00
+; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[IN]], 1.000000e+00
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP1]], float [[ADD]], float 1.000000e+00
+; CHECK-NEXT:    ret float [[SEL]]
+;
+  %cmp1 = fcmp olt float %in2, 0.000000e+00
+  %add = fadd float %in, 1.000000e+00
+  %sel = select i1 %cmp1, float %add, float 1.000000e+00
+  ret float %sel
+}
+
+define float @test_fmin_neg2(float %in) {
+; CHECK-LABEL: define float @test_fmin_neg2(
+; CHECK-SAME: float [[IN:%.*]]) {
+; CHECK-NEXT:    [[CMP1:%.*]] = fcmp olt float [[IN]], 1.000000e+00
+; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[IN]], 1.000000e+00
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP1]], float [[ADD]], float 1.000000e+00
+; CHECK-NEXT:    ret float [[SEL]]
+;
+  %cmp1 = fcmp olt float %in, 1.000000e+00
+  %add = fadd float %in, 1.000000e+00
+  %sel = select i1 %cmp1, float %add, float 1.000000e+00
+  ret float %sel
+}
+
+define float @test_fmin_neg3(float %in) {
+; CHECK-LABEL: define float @test_fmin_neg3(
+; CHECK-SAME: float [[IN:%.*]]) {
+; CHECK-NEXT:    [[CMP1:%.*]] = fcmp olt float [[IN]], 0.000000e+00
+; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[IN]], 1.000000e+00
+; CHECK-NEXT:    [[ADD_2:%.*]] = fadd float [[IN]], 1.000000e+00
+; CHECK-NEXT:    [[SEL_1:%.*]] = select i1 [[CMP1]], float [[ADD]], float 1.000000e+00
+; CHECK-NEXT:    [[SEL_2:%.*]] = select i1 [[CMP1]], float 2.000000e+00, float [[ADD_2]]
+; CHECK-NEXT:    [[RES:%.*]] = fadd float [[SEL_1]], [[SEL_2]]
+; CHECK-NEXT:    ret float [[RES]]
+;
+  %cmp1 = fcmp olt float %in, 0.000000e+00
+  %add = fadd float %in, 1.000000e+00
+  %add.2 = fadd float %in, 1.000000e+00
+  %sel.1 = select i1 %cmp1, float %add, float 1.000000e+00
+  %sel.2 = select i1 %cmp1, float 2.000000e+00, float %add.2
+  %res = fadd float %sel.1, %sel.2
+  ret float %res
+}

>From e6689625f63cfb73812ac3f4057adec0772570c6 Mon Sep 17 00:00:00 2001
From: rbajpai <rbajpai at nvidia.com>
Date: Mon, 2 Sep 2024 10:55:36 +0530
Subject: [PATCH 2/5] Addressed review comments.

---
 .../InstCombine/InstCombineSelect.cpp         |  67 +-
 .../InstCombine/fcmp-fadd-select.ll           | 627 ++++++++++++++----
 2 files changed, 548 insertions(+), 146 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index d22d13aec356b8..7103b3c9e8cd30 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -3699,42 +3699,56 @@ static bool hasAffectedValue(Value *V, SmallPtrSetImpl<Value *> &Affected,
   return false;
 }
 
-static Value *foldSelectAddConstant(SelectInst &SI,
-                                    InstCombiner::BuilderTy &Builder) {
-  Value *Cmp;
-  Instruction *FAdd;
-  ConstantFP *C;
-
-  // select((fcmp OGT/OLT, X, 0), (fadd X, C), C) => fadd((select (fcmp OGT/OLT,
-  // X, 0), X, 0), C)
+// This transformation enables the possibility of transforming fcmp + sel into
+// a fmaxnum/fminnum intrinsic.
+static Value *foldSelectIntoAddConstant(SelectInst &SI,
+                                        InstCombiner::BuilderTy &Builder) {
+  // Do this transformation only when select instruction gives NaN and NSZ
+  // guarantee.
+  auto *SIFOp = dyn_cast<FPMathOperator>(&SI);
+  if (!SIFOp || !SIFOp->hasNoSignedZeros() || !SIFOp->hasNoNaNs())
+    return nullptr;
 
-  // This transformation enables the possibility of transforming fcmp + sel into
-  // a fmax/fmin.
+  // select((fcmp Pred, X, 0), (fadd X, C), C)
+  //      => fadd((select (fcmp Pred, X, 0), X, 0), C)
+  //
+  // Pred := OGT, OGE, OLT, OLE, UGT, UGE, ULT, and ULE
+  Instruction *FAdd;
+  Constant *C;
+  Value *X, *Z;
+  CmpInst::Predicate Pred;
 
-  // OneUse check for `Cmp` is necessary because it makes sure that other
+  // Note: OneUse check for `Cmp` is necessary because it makes sure that other
   // InstCombine folds don't undo this transformation and cause an infinite
   // loop.
-  if (match(&SI, m_Select(m_OneUse(m_Value(Cmp)), m_OneUse(m_Instruction(FAdd)),
-                          m_ConstantFP(C))) ||
-      match(&SI, m_Select(m_OneUse(m_Value(Cmp)), m_ConstantFP(C),
-                          m_OneUse(m_Instruction(FAdd))))) {
-    Value *X;
-    CmpInst::Predicate Pred;
-    if (!match(Cmp, m_FCmp(Pred, m_Value(X), m_AnyZeroFP())))
+  if (match(&SI, m_Select(m_OneUse(m_FCmp(Pred, m_Value(X), m_Value(Z))),
+                          m_OneUse(m_Instruction(FAdd)), m_Constant(C))) ||
+      match(&SI, m_Select(m_OneUse(m_FCmp(Pred, m_Value(X), m_Value(Z))),
+                          m_Constant(C), m_OneUse(m_Instruction(FAdd))))) {
+    if (!match(Z, m_AnyZeroFP()))
       return nullptr;
 
-    if (Pred != CmpInst::FCMP_OGT && Pred != CmpInst::FCMP_OLT)
+    // Only these Predicates can be transformed into fmaxnum/fminnum intrinsic.
+    switch (Pred) {
+    default:
       return nullptr;
+    case FCmpInst::FCMP_OGT:
+    case FCmpInst::FCMP_OGE:
+    case FCmpInst::FCMP_OLT:
+    case FCmpInst::FCMP_OLE:
+    case FCmpInst::FCMP_UGT:
+    case FCmpInst::FCMP_UGE:
+    case FCmpInst::FCMP_ULT:
+    case FCmpInst::FCMP_ULE:
+      break;
+    }
 
     if (!match(FAdd, m_FAdd(m_Specific(X), m_Specific(C))))
       return nullptr;
 
-    FastMathFlags FMF = FAdd->getFastMathFlags();
-    FMF |= SI.getFastMathFlags();
-
-    Value *NewSelect = Builder.CreateSelect(
-        Cmp, X, ConstantFP::getZero(C->getType()), SI.getName() + ".new", &SI);
-    cast<Instruction>(NewSelect)->setFastMathFlags(FMF);
+    Value *NewSelect = Builder.CreateSelect(SI.getCondition(), X, Z,
+                                            SI.getName() + ".new", &SI);
+    cast<Instruction>(NewSelect)->setFastMathFlags(SI.getFastMathFlags());
 
     Value *NewFAdd =
         Builder.CreateFAddFMF(NewSelect, C, FAdd, FAdd->getName() + ".new");
@@ -4140,9 +4154,8 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
   if (Value *V = foldRoundUpIntegerWithPow2Alignment(SI, Builder))
     return replaceInstUsesWith(SI, V);
 
-  if (Value *V = foldSelectAddConstant(SI, Builder)) {
+  if (Value *V = foldSelectIntoAddConstant(SI, Builder))
     return replaceInstUsesWith(SI, V);
-  }
 
   // select(mask, mload(,,mask,0), 0) -> mload(,,mask,0)
   // Load inst is intentionally not checked for hasOneUse()
diff --git a/llvm/test/Transforms/InstCombine/fcmp-fadd-select.ll b/llvm/test/Transforms/InstCombine/fcmp-fadd-select.ll
index fced2d961b2415..b9717f78c79ab7 100644
--- a/llvm/test/Transforms/InstCombine/fcmp-fadd-select.ll
+++ b/llvm/test/Transforms/InstCombine/fcmp-fadd-select.ll
@@ -1,245 +1,634 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
 ; RUN: opt < %s -passes=instcombine -S | FileCheck %s
 
-; Check for fcmp + sel pattern which later lowered into fmax
-define float @test_fmax_pos1(float %in) {
-; CHECK-LABEL: define float @test_fmax_pos1(
+; fcmp OGT + fadd + sel => fcmp OGT + sel => fmaxnum
+
+define float @test_fcmp_ogt_fadd_select_constant(float %in) {
+; CHECK-LABEL: define float @test_fcmp_ogt_fadd_select_constant(
 ; CHECK-SAME: float [[IN:%.*]]) {
-; CHECK-NEXT:    [[CMP1:%.*]] = fcmp ogt float [[IN]], 0.000000e+00
-; CHECK-NEXT:    [[SEL_NEW:%.*]] = select i1 [[CMP1]], float [[IN]], float 0.000000e+00
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = call nnan nsz float @llvm.maxnum.f32(float [[IN]], float 0.000000e+00)
 ; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 1.000000e+00
 ; CHECK-NEXT:    ret float [[ADD_NEW]]
 ;
   %cmp1 = fcmp ogt float %in, 0.000000e+00
   %add = fadd float %in, 1.000000e+00
-  %sel = select i1 %cmp1, float %add, float 1.000000e+00
+  %sel = select nnan nsz i1 %cmp1, float %add, float 1.000000e+00
   ret float %sel
 }
 
-define float @test_fmax_pos2(float %in) {
-; CHECK-LABEL: define float @test_fmax_pos2(
+define float @test_fcmp_ogt_fadd_select_constant_swapped(float %in) {
+; CHECK-LABEL: define float @test_fcmp_ogt_fadd_select_constant_swapped(
 ; CHECK-SAME: float [[IN:%.*]]) {
-; CHECK-NEXT:    [[CMP1:%.*]] = fcmp ogt float [[IN]], 0.000000e+00
-; CHECK-NEXT:    [[SEL_NEW:%.*]] = select i1 [[CMP1]], float [[IN]], float 0.000000e+00
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = call nnan nsz float @llvm.maxnum.f32(float [[IN]], float 0.000000e+00)
 ; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 1.000000e+00
 ; CHECK-NEXT:    ret float [[ADD_NEW]]
 ;
   %cmp1 = fcmp ogt float %in, 0.000000e+00
   %add = fadd float %in, 1.000000e+00
-  %sel = select i1 %cmp1, float 1.000000e+00, float %add
+  %sel = select nnan nsz i1 %cmp1, float 1.000000e+00, float %add
   ret float %sel
 }
 
-define float @test_fmax_pos3(float %in) {
-; CHECK-LABEL: define float @test_fmax_pos3(
+define float @test_fcmp_ogt_fadd_select_neg_constant(float %in) {
+; CHECK-LABEL: define float @test_fcmp_ogt_fadd_select_neg_constant(
 ; CHECK-SAME: float [[IN:%.*]]) {
-; CHECK-NEXT:    [[CMP1:%.*]] = fcmp ogt float [[IN]], 0.000000e+00
-; CHECK-NEXT:    [[SEL_NEW:%.*]] = select i1 [[CMP1]], float [[IN]], float 0.000000e+00
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = call nnan nsz float @llvm.maxnum.f32(float [[IN]], float 0.000000e+00)
 ; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 1.000000e+00
 ; CHECK-NEXT:    ret float [[ADD_NEW]]
 ;
-  %cmp1 = fcmp ogt float %in, 0.000000e+00
-  %add = fadd float 1.000000e+00, %in
-  %sel = select i1 %cmp1, float %add, float 1.000000e+00
+  %cmp1 = fcmp ogt float %in, -0.000000e+00
+  %add = fadd float %in, 1.000000e+00
+  %sel = select nnan nsz i1 %cmp1, float %add, float 1.000000e+00
   ret float %sel
 }
 
-define float @test_fmax_pos4(float %in) {
-; CHECK-LABEL: define float @test_fmax_pos4(
+define float @test_fcmp_ogt_fadd_select_fastmath_preserve(float %in) {
+; CHECK-LABEL: define float @test_fcmp_ogt_fadd_select_fastmath_preserve(
 ; CHECK-SAME: float [[IN:%.*]]) {
-; CHECK-NEXT:    [[CMP1:%.*]] = fcmp ogt float [[IN]], 0.000000e+00
-; CHECK-NEXT:    [[SEL_NEW:%.*]] = select i1 [[CMP1]], float [[IN]], float 0.000000e+00
-; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 1.000000e+00
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = call nnan nsz float @llvm.maxnum.f32(float [[IN]], float 0.000000e+00)
+; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd nnan float [[SEL_NEW]], 1.000000e+00
 ; CHECK-NEXT:    ret float [[ADD_NEW]]
 ;
   %cmp1 = fcmp ogt float %in, 0.000000e+00
-  %add = fadd float 1.000000e+00, %in
-  %sel = select i1 %cmp1, float 1.000000e+00, float %add
+  %add = fadd nnan float %in, 1.000000e+00
+  %sel = select nnan nsz i1 %cmp1, float %add, float 1.000000e+00
   ret float %sel
 }
 
-define float @test_fmax_pos5(float %in) {
-; CHECK-LABEL: define float @test_fmax_pos5(
+define <2 x float> @test_fcmp_ogt_fadd_select_constant_vectors(<2 x float> %in) {
+; CHECK-LABEL: define <2 x float> @test_fcmp_ogt_fadd_select_constant_vectors(
+; CHECK-SAME: <2 x float> [[IN:%.*]]) {
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = call nnan nsz <2 x float> @llvm.maxnum.v2f32(<2 x float> [[IN]], <2 x float> zeroinitializer)
+; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd <2 x float> [[SEL_NEW]], <float 1.000000e+00, float 1.000000e+00>
+; CHECK-NEXT:    ret <2 x float> [[ADD_NEW]]
+;
+  %cmp1 = fcmp ogt <2 x float> %in, <float 0.000000e+00, float 0.000000e+00>
+  %add = fadd <2 x float> %in, <float 1.000000e+00, float 1.000000e+00>
+  %sel = select nnan nsz <2 x i1> %cmp1, <2 x float> %add, <2 x float> <float 1.000000e+00, float 1.000000e+00>
+  ret <2 x float> %sel
+}
+
+
+; fcmp OLT + fadd + sel => fcmp OLT + sel => fminnum
+
+define float @test_fcmp_olt_fadd_select_constant(float %in) {
+; CHECK-LABEL: define float @test_fcmp_olt_fadd_select_constant(
 ; CHECK-SAME: float [[IN:%.*]]) {
-; CHECK-NEXT:    [[CMP1:%.*]] = fcmp ogt float [[IN]], 0.000000e+00
-; CHECK-NEXT:    [[SEL_NEW:%.*]] = select i1 [[CMP1]], float [[IN]], float 0.000000e+00
-; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 2.000000e+00
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = call nnan nsz float @llvm.minnum.f32(float [[IN]], float 0.000000e+00)
+; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 1.000000e+00
 ; CHECK-NEXT:    ret float [[ADD_NEW]]
 ;
-  %cmp1 = fcmp ogt float %in, 0.000000e+00
-  %add = fadd float 2.000000e+00, %in
-  %sel = select i1 %cmp1, float 2.000000e+00, float %add
+  %cmp1 = fcmp olt float %in, 0.000000e+00
+  %add = fadd float %in, 1.000000e+00
+  %sel = select nnan nsz i1 %cmp1, float %add, float 1.000000e+00
   ret float %sel
 }
 
-
-; Check for fcmp + sel pattern which later lowered into fmin
-define float @test_fmin_pos1(float %in) {
-; CHECK-LABEL: define float @test_fmin_pos1(
+define float @test_fcmp_olt_fadd_select_constant_swapped(float %in) {
+; CHECK-LABEL: define float @test_fcmp_olt_fadd_select_constant_swapped(
 ; CHECK-SAME: float [[IN:%.*]]) {
-; CHECK-NEXT:    [[CMP1:%.*]] = fcmp olt float [[IN]], 0.000000e+00
-; CHECK-NEXT:    [[SEL_NEW:%.*]] = select i1 [[CMP1]], float [[IN]], float 0.000000e+00
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = call nnan nsz float @llvm.minnum.f32(float [[IN]], float 0.000000e+00)
 ; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 1.000000e+00
 ; CHECK-NEXT:    ret float [[ADD_NEW]]
 ;
   %cmp1 = fcmp olt float %in, 0.000000e+00
   %add = fadd float %in, 1.000000e+00
-  %sel = select i1 %cmp1, float %add, float 1.000000e+00
+  %sel = select nnan nsz i1 %cmp1, float 1.000000e+00, float %add
   ret float %sel
 }
 
-define float @test_fmin_pos2(float %in) {
-; CHECK-LABEL: define float @test_fmin_pos2(
+define float @test_fcmp_olt_fadd_select_neg_constant(float %in) {
+; CHECK-LABEL: define float @test_fcmp_olt_fadd_select_neg_constant(
 ; CHECK-SAME: float [[IN:%.*]]) {
-; CHECK-NEXT:    [[CMP1:%.*]] = fcmp olt float [[IN]], 0.000000e+00
-; CHECK-NEXT:    [[SEL_NEW:%.*]] = select i1 [[CMP1]], float [[IN]], float 0.000000e+00
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = call nnan nsz float @llvm.minnum.f32(float [[IN]], float 0.000000e+00)
 ; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 1.000000e+00
 ; CHECK-NEXT:    ret float [[ADD_NEW]]
+;
+  %cmp1 = fcmp olt float %in, -0.000000e+00
+  %add = fadd float %in, 1.000000e+00
+  %sel = select nnan nsz i1 %cmp1, float %add, float 1.000000e+00
+  ret float %sel
+}
+
+define float @test_fcmp_olt_fadd_select_fastmath_preserve(float %in) {
+; CHECK-LABEL: define float @test_fcmp_olt_fadd_select_fastmath_preserve(
+; CHECK-SAME: float [[IN:%.*]]) {
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = call nnan nsz float @llvm.minnum.f32(float [[IN]], float 0.000000e+00)
+; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd nnan float [[SEL_NEW]], 1.000000e+00
+; CHECK-NEXT:    ret float [[ADD_NEW]]
 ;
   %cmp1 = fcmp olt float %in, 0.000000e+00
+  %add = fadd nnan float %in, 1.000000e+00
+  %sel = select nnan nsz i1 %cmp1, float %add, float 1.000000e+00
+  ret float %sel
+}
+
+define <2 x float> @test_fcmp_olt_fadd_select_constant_vectors(<2 x float> %in) {
+; CHECK-LABEL: define <2 x float> @test_fcmp_olt_fadd_select_constant_vectors(
+; CHECK-SAME: <2 x float> [[IN:%.*]]) {
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = call nnan nsz <2 x float> @llvm.minnum.v2f32(<2 x float> [[IN]], <2 x float> zeroinitializer)
+; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd <2 x float> [[SEL_NEW]], <float 1.000000e+00, float 1.000000e+00>
+; CHECK-NEXT:    ret <2 x float> [[ADD_NEW]]
+;
+  %cmp1 = fcmp olt <2 x float> %in, <float 0.000000e+00, float 0.000000e+00>
+  %add = fadd <2 x float> %in, <float 1.000000e+00, float 1.000000e+00>
+  %sel = select nnan nsz <2 x i1> %cmp1, <2 x float> %add, <2 x float> <float 1.000000e+00, float 1.000000e+00>
+  ret <2 x float> %sel
+}
+
+
+; fcmp OGE + fadd + sel => fcmp OGE + sel => fmaxnum
+
+define float @test_fcmp_oge_fadd_select_constant(float %in) {
+; CHECK-LABEL: define float @test_fcmp_oge_fadd_select_constant(
+; CHECK-SAME: float [[IN:%.*]]) {
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = call nnan nsz float @llvm.maxnum.f32(float [[IN]], float 0.000000e+00)
+; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 1.000000e+00
+; CHECK-NEXT:    ret float [[ADD_NEW]]
+;
+  %cmp1 = fcmp oge float %in, 0.000000e+00
   %add = fadd float %in, 1.000000e+00
-  %sel = select i1 %cmp1, float 1.000000e+00, float %add
+  %sel = select nnan nsz i1 %cmp1, float %add, float 1.000000e+00
   ret float %sel
 }
 
-define float @test_fmin_pos3(float %in) {
-; CHECK-LABEL: define float @test_fmin_pos3(
+define float @test_fcmp_oge_fadd_select_constant_swapped(float %in) {
+; CHECK-LABEL: define float @test_fcmp_oge_fadd_select_constant_swapped(
 ; CHECK-SAME: float [[IN:%.*]]) {
-; CHECK-NEXT:    [[CMP1:%.*]] = fcmp olt float [[IN]], 0.000000e+00
-; CHECK-NEXT:    [[SEL_NEW:%.*]] = select i1 [[CMP1]], float [[IN]], float 0.000000e+00
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = call nnan nsz float @llvm.maxnum.f32(float [[IN]], float 0.000000e+00)
 ; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 1.000000e+00
 ; CHECK-NEXT:    ret float [[ADD_NEW]]
 ;
-  %cmp1 = fcmp olt float %in, 0.000000e+00
-  %add = fadd float 1.000000e+00, %in
-  %sel = select i1 %cmp1, float %add, float 1.000000e+00
+  %cmp1 = fcmp oge float %in, 0.000000e+00
+  %add = fadd float %in, 1.000000e+00
+  %sel = select nnan nsz i1 %cmp1, float 1.000000e+00, float %add
   ret float %sel
 }
 
-define float @test_fmin_pos4(float %in) {
-; CHECK-LABEL: define float @test_fmin_pos4(
+define float @test_fcmp_oge_fadd_select_neg_constant(float %in) {
+; CHECK-LABEL: define float @test_fcmp_oge_fadd_select_neg_constant(
 ; CHECK-SAME: float [[IN:%.*]]) {
-; CHECK-NEXT:    [[CMP1:%.*]] = fcmp olt float [[IN]], 0.000000e+00
-; CHECK-NEXT:    [[SEL_NEW:%.*]] = select i1 [[CMP1]], float [[IN]], float 0.000000e+00
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = call nnan nsz float @llvm.maxnum.f32(float [[IN]], float 0.000000e+00)
 ; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 1.000000e+00
 ; CHECK-NEXT:    ret float [[ADD_NEW]]
 ;
-  %cmp1 = fcmp olt float %in, 0.000000e+00
-  %add = fadd float 1.000000e+00, %in
-  %sel = select i1 %cmp1, float 1.000000e+00, float %add
+  %cmp1 = fcmp oge float %in, -0.000000e+00
+  %add = fadd float %in, 1.000000e+00
+  %sel = select nnan nsz i1 %cmp1, float %add, float 1.000000e+00
   ret float %sel
 }
 
-define float @test_fmin_pos5(float %in) {
-; CHECK-LABEL: define float @test_fmin_pos5(
+define float @test_fcmp_oge_fadd_select_fastmath_preserve(float %in) {
+; CHECK-LABEL: define float @test_fcmp_oge_fadd_select_fastmath_preserve(
 ; CHECK-SAME: float [[IN:%.*]]) {
-; CHECK-NEXT:    [[CMP1:%.*]] = fcmp olt float [[IN]], 0.000000e+00
-; CHECK-NEXT:    [[SEL_NEW:%.*]] = select i1 [[CMP1]], float [[IN]], float 0.000000e+00
-; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 2.000000e+00
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = call nnan nsz float @llvm.maxnum.f32(float [[IN]], float 0.000000e+00)
+; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd nnan float [[SEL_NEW]], 1.000000e+00
 ; CHECK-NEXT:    ret float [[ADD_NEW]]
 ;
-  %cmp1 = fcmp olt float %in, 0.000000e+00
-  %add = fadd float 2.000000e+00, %in
-  %sel = select i1 %cmp1, float 2.000000e+00, float %add
+  %cmp1 = fcmp oge float %in, 0.000000e+00
+  %add = fadd nnan float %in, 1.000000e+00
+  %sel = select nnan nsz i1 %cmp1, float %add, float 1.000000e+00
   ret float %sel
 }
 
+define <2 x float> @test_fcmp_oge_fadd_select_constant_vectors(<2 x float> %in) {
+; CHECK-LABEL: define <2 x float> @test_fcmp_oge_fadd_select_constant_vectors(
+; CHECK-SAME: <2 x float> [[IN:%.*]]) {
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = call nnan nsz <2 x float> @llvm.maxnum.v2f32(<2 x float> [[IN]], <2 x float> zeroinitializer)
+; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd <2 x float> [[SEL_NEW]], <float 1.000000e+00, float 1.000000e+00>
+; CHECK-NEXT:    ret <2 x float> [[ADD_NEW]]
+;
+  %cmp1 = fcmp oge <2 x float> %in, <float 0.000000e+00, float 0.000000e+00>
+  %add = fadd <2 x float> %in, <float 1.000000e+00, float 1.000000e+00>
+  %sel = select nnan nsz <2 x i1> %cmp1, <2 x float> %add, <2 x float> <float 1.000000e+00, float 1.000000e+00>
+  ret <2 x float> %sel
+}
 
-; Check for fmax scenarios that shouldn't be transformed.
-define float @test_fmax_neg1(float %in, float %in2) {
-; CHECK-LABEL: define float @test_fmax_neg1(
-; CHECK-SAME: float [[IN:%.*]], float [[IN2:%.*]]) {
-; CHECK-NEXT:    [[CMP1:%.*]] = fcmp ogt float [[IN2]], 0.000000e+00
-; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[IN]], 1.000000e+00
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP1]], float [[ADD]], float 1.000000e+00
-; CHECK-NEXT:    ret float [[SEL]]
+
+; fcmp OLE + fadd + sel => fcmp OLE + sel => fminnum
+
+define float @test_fcmp_ole_fadd_select_constant(float %in) {
+; CHECK-LABEL: define float @test_fcmp_ole_fadd_select_constant(
+; CHECK-SAME: float [[IN:%.*]]) {
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = call nnan nsz float @llvm.minnum.f32(float [[IN]], float 0.000000e+00)
+; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 1.000000e+00
+; CHECK-NEXT:    ret float [[ADD_NEW]]
 ;
-  %cmp1 = fcmp ogt float %in2, 0.000000e+00
+  %cmp1 = fcmp ole float %in, 0.000000e+00
   %add = fadd float %in, 1.000000e+00
-  %sel = select i1 %cmp1, float %add, float 1.000000e+00
+  %sel = select nnan nsz i1 %cmp1, float %add, float 1.000000e+00
   ret float %sel
 }
 
-define float @test_fmax_neg2(float %in) {
-; CHECK-LABEL: define float @test_fmax_neg2(
+define float @test_fcmp_ole_fadd_select_constant_swapped(float %in) {
+; CHECK-LABEL: define float @test_fcmp_ole_fadd_select_constant_swapped(
 ; CHECK-SAME: float [[IN:%.*]]) {
-; CHECK-NEXT:    [[CMP1:%.*]] = fcmp ogt float [[IN]], 1.000000e+00
-; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[IN]], 1.000000e+00
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP1]], float [[ADD]], float 1.000000e+00
-; CHECK-NEXT:    ret float [[SEL]]
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = call nnan nsz float @llvm.minnum.f32(float [[IN]], float 0.000000e+00)
+; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 1.000000e+00
+; CHECK-NEXT:    ret float [[ADD_NEW]]
 ;
-  %cmp1 = fcmp ogt float %in, 1.000000e+00
+  %cmp1 = fcmp ole float %in, 0.000000e+00
   %add = fadd float %in, 1.000000e+00
-  %sel = select i1 %cmp1, float %add, float 1.000000e+00
+  %sel = select nnan nsz i1 %cmp1, float 1.000000e+00, float %add
+  ret float %sel
+}
+
+define float @test_fcmp_ole_fadd_select_neg_constant(float %in) {
+; CHECK-LABEL: define float @test_fcmp_ole_fadd_select_neg_constant(
+; CHECK-SAME: float [[IN:%.*]]) {
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = call nnan nsz float @llvm.minnum.f32(float [[IN]], float 0.000000e+00)
+; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 1.000000e+00
+; CHECK-NEXT:    ret float [[ADD_NEW]]
+;
+  %cmp1 = fcmp ole float %in, -0.000000e+00
+  %add = fadd float %in, 1.000000e+00
+  %sel = select nnan nsz i1 %cmp1, float %add, float 1.000000e+00
+  ret float %sel
+}
+
+define float @test_fcmp_ole_fadd_select_fastmath_preserve(float %in) {
+; CHECK-LABEL: define float @test_fcmp_ole_fadd_select_fastmath_preserve(
+; CHECK-SAME: float [[IN:%.*]]) {
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = call nnan nsz float @llvm.minnum.f32(float [[IN]], float 0.000000e+00)
+; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd nnan float [[SEL_NEW]], 1.000000e+00
+; CHECK-NEXT:    ret float [[ADD_NEW]]
+;
+  %cmp1 = fcmp ole float %in, 0.000000e+00
+  %add = fadd nnan float %in, 1.000000e+00
+  %sel = select nnan nsz i1 %cmp1, float %add, float 1.000000e+00
+  ret float %sel
+}
+
+define <2 x float> @test_fcmp_ole_fadd_select_constant_vectors(<2 x float> %in) {
+; CHECK-LABEL: define <2 x float> @test_fcmp_ole_fadd_select_constant_vectors(
+; CHECK-SAME: <2 x float> [[IN:%.*]]) {
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = call nnan nsz <2 x float> @llvm.minnum.v2f32(<2 x float> [[IN]], <2 x float> zeroinitializer)
+; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd <2 x float> [[SEL_NEW]], <float 1.000000e+00, float 1.000000e+00>
+; CHECK-NEXT:    ret <2 x float> [[ADD_NEW]]
+;
+  %cmp1 = fcmp ole <2 x float> %in, <float 0.000000e+00, float 0.000000e+00>
+  %add = fadd <2 x float> %in, <float 1.000000e+00, float 1.000000e+00>
+  %sel = select nnan nsz <2 x i1> %cmp1, <2 x float> %add, <2 x float> <float 1.000000e+00, float 1.000000e+00>
+  ret <2 x float> %sel
+}
+
+
+; fcmp UGT + fadd + sel => fcmp UGT + sel => fcmp OLE + sel
+
+define float @test_fcmp_ugt_fadd_select_constant(float %in) {
+; CHECK-LABEL: define float @test_fcmp_ugt_fadd_select_constant(
+; CHECK-SAME: float [[IN:%.*]]) {
+; CHECK-NEXT:    [[CMP1_INV:%.*]] = fcmp ole float [[IN]], 0.000000e+00
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = select i1 [[CMP1_INV]], float 0.000000e+00, float [[IN]]
+; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 1.000000e+00
+; CHECK-NEXT:    ret float [[ADD_NEW]]
+;
+  %cmp1 = fcmp ugt float %in, 0.000000e+00
+  %add = fadd float %in, 1.000000e+00
+  %sel = select nnan nsz i1 %cmp1, float %add, float 1.000000e+00
+  ret float %sel
+}
+
+define float @test_fcmp_ugt_fadd_select_constant_swapped(float %in) {
+; CHECK-LABEL: define float @test_fcmp_ugt_fadd_select_constant_swapped(
+; CHECK-SAME: float [[IN:%.*]]) {
+; CHECK-NEXT:    [[CMP1_INV:%.*]] = fcmp ole float [[IN]], 0.000000e+00
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = select i1 [[CMP1_INV]], float 0.000000e+00, float [[IN]]
+; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 1.000000e+00
+; CHECK-NEXT:    ret float [[ADD_NEW]]
+;
+  %cmp1 = fcmp ugt float %in, 0.000000e+00
+  %add = fadd float %in, 1.000000e+00
+  %sel = select nnan nsz i1 %cmp1, float 1.000000e+00, float %add
+  ret float %sel
+}
+
+define float @test_fcmp_ugt_fadd_select_neg_constant(float %in) {
+; CHECK-LABEL: define float @test_fcmp_ugt_fadd_select_neg_constant(
+; CHECK-SAME: float [[IN:%.*]]) {
+; CHECK-NEXT:    [[CMP1_INV:%.*]] = fcmp ole float [[IN]], 0.000000e+00
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = select i1 [[CMP1_INV]], float 0.000000e+00, float [[IN]]
+; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 1.000000e+00
+; CHECK-NEXT:    ret float [[ADD_NEW]]
+;
+  %cmp1 = fcmp ugt float %in, -0.000000e+00
+  %add = fadd float %in, 1.000000e+00
+  %sel = select nnan nsz i1 %cmp1, float %add, float 1.000000e+00
+  ret float %sel
+}
+
+define float @test_fcmp_ugt_fadd_select_fastmath_preserve(float %in) {
+; CHECK-LABEL: define float @test_fcmp_ugt_fadd_select_fastmath_preserve(
+; CHECK-SAME: float [[IN:%.*]]) {
+; CHECK-NEXT:    [[CMP1_INV:%.*]] = fcmp ole float [[IN]], 0.000000e+00
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = select i1 [[CMP1_INV]], float 0.000000e+00, float [[IN]]
+; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd nnan float [[SEL_NEW]], 1.000000e+00
+; CHECK-NEXT:    ret float [[ADD_NEW]]
+;
+  %cmp1 = fcmp ugt float %in, 0.000000e+00
+  %add = fadd nnan float %in, 1.000000e+00
+  %sel = select nnan nsz i1 %cmp1, float %add, float 1.000000e+00
+  ret float %sel
+}
+
+define <2 x float> @test_fcmp_ugt_fadd_select_constant_vectors(<2 x float> %in) {
+; CHECK-LABEL: define <2 x float> @test_fcmp_ugt_fadd_select_constant_vectors(
+; CHECK-SAME: <2 x float> [[IN:%.*]]) {
+; CHECK-NEXT:    [[CMP1_INV:%.*]] = fcmp ole <2 x float> [[IN]], zeroinitializer
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = select <2 x i1> [[CMP1_INV]], <2 x float> zeroinitializer, <2 x float> [[IN]]
+; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd <2 x float> [[SEL_NEW]], <float 1.000000e+00, float 1.000000e+00>
+; CHECK-NEXT:    ret <2 x float> [[ADD_NEW]]
+;
+  %cmp1 = fcmp ugt <2 x float> %in, <float 0.000000e+00, float 0.000000e+00>
+  %add = fadd <2 x float> %in, <float 1.000000e+00, float 1.000000e+00>
+  %sel = select nnan nsz <2 x i1> %cmp1, <2 x float> %add, <2 x float> <float 1.000000e+00, float 1.000000e+00>
+  ret <2 x float> %sel
+}
+
+
+; fcmp UGE + fadd + sel => fcmp UGE + sel => fcmp olt + sel
+
+define float @test_fcmp_uge_fadd_select_constant(float %in) {
+; CHECK-LABEL: define float @test_fcmp_uge_fadd_select_constant(
+; CHECK-SAME: float [[IN:%.*]]) {
+; CHECK-NEXT:    [[CMP1_INV:%.*]] = fcmp olt float [[IN]], 0.000000e+00
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = select i1 [[CMP1_INV]], float 0.000000e+00, float [[IN]]
+; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 1.000000e+00
+; CHECK-NEXT:    ret float [[ADD_NEW]]
+;
+  %cmp1 = fcmp uge float %in, 0.000000e+00
+  %add = fadd float %in, 1.000000e+00
+  %sel = select nnan nsz i1 %cmp1, float %add, float 1.000000e+00
+  ret float %sel
+}
+
+define float @test_fcmp_uge_fadd_select_constant_swapped(float %in) {
+; CHECK-LABEL: define float @test_fcmp_uge_fadd_select_constant_swapped(
+; CHECK-SAME: float [[IN:%.*]]) {
+; CHECK-NEXT:    [[CMP1_INV:%.*]] = fcmp olt float [[IN]], 0.000000e+00
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = select i1 [[CMP1_INV]], float 0.000000e+00, float [[IN]]
+; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 1.000000e+00
+; CHECK-NEXT:    ret float [[ADD_NEW]]
+;
+  %cmp1 = fcmp uge float %in, 0.000000e+00
+  %add = fadd float %in, 1.000000e+00
+  %sel = select nnan nsz i1 %cmp1, float 1.000000e+00, float %add
+  ret float %sel
+}
+
+define float @test_fcmp_uge_fadd_select_neg_constant(float %in) {
+; CHECK-LABEL: define float @test_fcmp_uge_fadd_select_neg_constant(
+; CHECK-SAME: float [[IN:%.*]]) {
+; CHECK-NEXT:    [[CMP1_INV:%.*]] = fcmp olt float [[IN]], 0.000000e+00
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = select i1 [[CMP1_INV]], float 0.000000e+00, float [[IN]]
+; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 1.000000e+00
+; CHECK-NEXT:    ret float [[ADD_NEW]]
+;
+  %cmp1 = fcmp uge float %in, -0.000000e+00
+  %add = fadd float %in, 1.000000e+00
+  %sel = select nnan nsz i1 %cmp1, float %add, float 1.000000e+00
   ret float %sel
 }
 
-define float @test_fmax_neg3(float %in) {
-; CHECK-LABEL: define float @test_fmax_neg3(
+define float @test_fcmp_uge_fadd_select_fastmath_preserve(float %in) {
+; CHECK-LABEL: define float @test_fcmp_uge_fadd_select_fastmath_preserve(
+; CHECK-SAME: float [[IN:%.*]]) {
+; CHECK-NEXT:    [[CMP1_INV:%.*]] = fcmp olt float [[IN]], 0.000000e+00
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = select i1 [[CMP1_INV]], float 0.000000e+00, float [[IN]]
+; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd nnan float [[SEL_NEW]], 1.000000e+00
+; CHECK-NEXT:    ret float [[ADD_NEW]]
+;
+  %cmp1 = fcmp uge float %in, 0.000000e+00
+  %add = fadd nnan float %in, 1.000000e+00
+  %sel = select nnan nsz i1 %cmp1, float %add, float 1.000000e+00
+  ret float %sel
+}
+
+define <2 x float> @test_fcmp_uge_fadd_select_constant_vectors(<2 x float> %in) {
+; CHECK-LABEL: define <2 x float> @test_fcmp_uge_fadd_select_constant_vectors(
+; CHECK-SAME: <2 x float> [[IN:%.*]]) {
+; CHECK-NEXT:    [[CMP1_INV:%.*]] = fcmp olt <2 x float> [[IN]], zeroinitializer
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = select <2 x i1> [[CMP1_INV]], <2 x float> zeroinitializer, <2 x float> [[IN]]
+; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd <2 x float> [[SEL_NEW]], <float 1.000000e+00, float 1.000000e+00>
+; CHECK-NEXT:    ret <2 x float> [[ADD_NEW]]
+;
+  %cmp1 = fcmp uge <2 x float> %in, <float 0.000000e+00, float 0.000000e+00>
+  %add = fadd <2 x float> %in, <float 1.000000e+00, float 1.000000e+00>
+  %sel = select nnan nsz <2 x i1> %cmp1, <2 x float> %add, <2 x float> <float 1.000000e+00, float 1.000000e+00>
+  ret <2 x float> %sel
+}
+
+
+; fcmp ULT + fadd + sel => fcmp ULT + sel => fcmp OGE + sel
+
+define float @test_fcmp_ult_fadd_select_constant(float %in) {
+; CHECK-LABEL: define float @test_fcmp_ult_fadd_select_constant(
+; CHECK-SAME: float [[IN:%.*]]) {
+; CHECK-NEXT:    [[CMP1_INV:%.*]] = fcmp oge float [[IN]], 0.000000e+00
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = select i1 [[CMP1_INV]], float 0.000000e+00, float [[IN]]
+; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 1.000000e+00
+; CHECK-NEXT:    ret float [[ADD_NEW]]
+;
+  %cmp1 = fcmp ult float %in, 0.000000e+00
+  %add = fadd float %in, 1.000000e+00
+  %sel = select nnan nsz i1 %cmp1, float %add, float 1.000000e+00
+  ret float %sel
+}
+
+define float @test_fcmp_ult_fadd_select_constant_swapped(float %in) {
+; CHECK-LABEL: define float @test_fcmp_ult_fadd_select_constant_swapped(
+; CHECK-SAME: float [[IN:%.*]]) {
+; CHECK-NEXT:    [[CMP1_INV:%.*]] = fcmp oge float [[IN]], 0.000000e+00
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = select i1 [[CMP1_INV]], float 0.000000e+00, float [[IN]]
+; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 1.000000e+00
+; CHECK-NEXT:    ret float [[ADD_NEW]]
+;
+  %cmp1 = fcmp ult float %in, 0.000000e+00
+  %add = fadd float %in, 1.000000e+00
+  %sel = select nnan nsz i1 %cmp1, float 1.000000e+00, float %add
+  ret float %sel
+}
+
+define float @test_fcmp_ult_fadd_select_neg_constant(float %in) {
+; CHECK-LABEL: define float @test_fcmp_ult_fadd_select_neg_constant(
+; CHECK-SAME: float [[IN:%.*]]) {
+; CHECK-NEXT:    [[CMP1_INV:%.*]] = fcmp oge float [[IN]], 0.000000e+00
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = select i1 [[CMP1_INV]], float 0.000000e+00, float [[IN]]
+; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 1.000000e+00
+; CHECK-NEXT:    ret float [[ADD_NEW]]
+;
+  %cmp1 = fcmp ult float %in, -0.000000e+00
+  %add = fadd float %in, 1.000000e+00
+  %sel = select nnan nsz i1 %cmp1, float %add, float 1.000000e+00
+  ret float %sel
+}
+
+define float @test_fcmp_ult_fadd_select_fastmath_preserve(float %in) {
+; CHECK-LABEL: define float @test_fcmp_ult_fadd_select_fastmath_preserve(
+; CHECK-SAME: float [[IN:%.*]]) {
+; CHECK-NEXT:    [[CMP1_INV:%.*]] = fcmp oge float [[IN]], 0.000000e+00
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = select i1 [[CMP1_INV]], float 0.000000e+00, float [[IN]]
+; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd nnan float [[SEL_NEW]], 1.000000e+00
+; CHECK-NEXT:    ret float [[ADD_NEW]]
+;
+  %cmp1 = fcmp ult float %in, 0.000000e+00
+  %add = fadd nnan float %in, 1.000000e+00
+  %sel = select nnan nsz i1 %cmp1, float %add, float 1.000000e+00
+  ret float %sel
+}
+
+define <2 x float> @test_fcmp_ult_fadd_select_constant_vectors(<2 x float> %in) {
+; CHECK-LABEL: define <2 x float> @test_fcmp_ult_fadd_select_constant_vectors(
+; CHECK-SAME: <2 x float> [[IN:%.*]]) {
+; CHECK-NEXT:    [[CMP1_INV:%.*]] = fcmp oge <2 x float> [[IN]], zeroinitializer
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = select <2 x i1> [[CMP1_INV]], <2 x float> zeroinitializer, <2 x float> [[IN]]
+; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd <2 x float> [[SEL_NEW]], <float 1.000000e+00, float 1.000000e+00>
+; CHECK-NEXT:    ret <2 x float> [[ADD_NEW]]
+;
+  %cmp1 = fcmp ult <2 x float> %in, <float 0.000000e+00, float 0.000000e+00>
+  %add = fadd <2 x float> %in, <float 1.000000e+00, float 1.000000e+00>
+  %sel = select nnan nsz <2 x i1> %cmp1, <2 x float> %add, <2 x float> <float 1.000000e+00, float 1.000000e+00>
+  ret <2 x float> %sel
+}
+
+
+; fcmp ULE + fadd + sel => fcmp ULE + sel => fcmp OGT + sel
+
+define float @test_fcmp_ule_fadd_select_constant(float %in) {
+; CHECK-LABEL: define float @test_fcmp_ule_fadd_select_constant(
+; CHECK-SAME: float [[IN:%.*]]) {
+; CHECK-NEXT:    [[CMP1_INV:%.*]] = fcmp ogt float [[IN]], 0.000000e+00
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = select i1 [[CMP1_INV]], float 0.000000e+00, float [[IN]]
+; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 1.000000e+00
+; CHECK-NEXT:    ret float [[ADD_NEW]]
+;
+  %cmp1 = fcmp ule float %in, 0.000000e+00
+  %add = fadd float %in, 1.000000e+00
+  %sel = select nnan nsz i1 %cmp1, float %add, float 1.000000e+00
+  ret float %sel
+}
+
+define float @test_fcmp_ule_fadd_select_constant_swapped(float %in) {
+; CHECK-LABEL: define float @test_fcmp_ule_fadd_select_constant_swapped(
+; CHECK-SAME: float [[IN:%.*]]) {
+; CHECK-NEXT:    [[CMP1_INV:%.*]] = fcmp ogt float [[IN]], 0.000000e+00
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = select i1 [[CMP1_INV]], float 0.000000e+00, float [[IN]]
+; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 1.000000e+00
+; CHECK-NEXT:    ret float [[ADD_NEW]]
+;
+  %cmp1 = fcmp ule float %in, 0.000000e+00
+  %add = fadd float %in, 1.000000e+00
+  %sel = select nnan nsz i1 %cmp1, float 1.000000e+00, float %add
+  ret float %sel
+}
+
+define float @test_fcmp_ule_fadd_select_neg_constant(float %in) {
+; CHECK-LABEL: define float @test_fcmp_ule_fadd_select_neg_constant(
+; CHECK-SAME: float [[IN:%.*]]) {
+; CHECK-NEXT:    [[CMP1_INV:%.*]] = fcmp ogt float [[IN]], 0.000000e+00
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = select i1 [[CMP1_INV]], float 0.000000e+00, float [[IN]]
+; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd float [[SEL_NEW]], 1.000000e+00
+; CHECK-NEXT:    ret float [[ADD_NEW]]
+;
+  %cmp1 = fcmp ule float %in, -0.000000e+00
+  %add = fadd float %in, 1.000000e+00
+  %sel = select nnan nsz i1 %cmp1, float %add, float 1.000000e+00
+  ret float %sel
+}
+
+define float @test_fcmp_ule_fadd_select_fastmath_preserve(float %in) {
+; CHECK-LABEL: define float @test_fcmp_ule_fadd_select_fastmath_preserve(
+; CHECK-SAME: float [[IN:%.*]]) {
+; CHECK-NEXT:    [[CMP1_INV:%.*]] = fcmp ogt float [[IN]], 0.000000e+00
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = select i1 [[CMP1_INV]], float 0.000000e+00, float [[IN]]
+; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd nnan float [[SEL_NEW]], 1.000000e+00
+; CHECK-NEXT:    ret float [[ADD_NEW]]
+;
+  %cmp1 = fcmp ule float %in, 0.000000e+00
+  %add = fadd nnan float %in, 1.000000e+00
+  %sel = select nnan nsz i1 %cmp1, float %add, float 1.000000e+00
+  ret float %sel
+}
+
+define <2 x float> @test_fcmp_ule_fadd_select_constant_vectors(<2 x float> %in) {
+; CHECK-LABEL: define <2 x float> @test_fcmp_ule_fadd_select_constant_vectors(
+; CHECK-SAME: <2 x float> [[IN:%.*]]) {
+; CHECK-NEXT:    [[CMP1_INV:%.*]] = fcmp ogt <2 x float> [[IN]], zeroinitializer
+; CHECK-NEXT:    [[SEL_NEW:%.*]] = select <2 x i1> [[CMP1_INV]], <2 x float> zeroinitializer, <2 x float> [[IN]]
+; CHECK-NEXT:    [[ADD_NEW:%.*]] = fadd <2 x float> [[SEL_NEW]], <float 1.000000e+00, float 1.000000e+00>
+; CHECK-NEXT:    ret <2 x float> [[ADD_NEW]]
+;
+  %cmp1 = fcmp ule <2 x float> %in, <float 0.000000e+00, float 0.000000e+00>
+  %add = fadd <2 x float> %in, <float 1.000000e+00, float 1.000000e+00>
+  %sel = select nnan nsz <2 x i1> %cmp1, <2 x float> %add, <2 x float> <float 1.000000e+00, float 1.000000e+00>
+  ret <2 x float> %sel
+}
+
+
+; Negative scenarios
+
+; select instruction doesn't give nnan and nsz guarantees.
+define float @test_select_without_nnan_nsz(float %in) {
+; CHECK-LABEL: define float @test_select_without_nnan_nsz(
 ; CHECK-SAME: float [[IN:%.*]]) {
 ; CHECK-NEXT:    [[CMP1:%.*]] = fcmp ogt float [[IN]], 0.000000e+00
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[IN]], 1.000000e+00
-; CHECK-NEXT:    [[ADD_2:%.*]] = fadd float [[IN]], 1.000000e+00
-; CHECK-NEXT:    [[SEL_1:%.*]] = select i1 [[CMP1]], float [[ADD]], float 1.000000e+00
-; CHECK-NEXT:    [[SEL_2:%.*]] = select i1 [[CMP1]], float 2.000000e+00, float [[ADD_2]]
-; CHECK-NEXT:    [[RES:%.*]] = fadd float [[SEL_1]], [[SEL_2]]
-; CHECK-NEXT:    ret float [[RES]]
+; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP1]], float [[ADD]], float 1.000000e+00
+; CHECK-NEXT:    ret float [[SEL]]
 ;
   %cmp1 = fcmp ogt float %in, 0.000000e+00
   %add = fadd float %in, 1.000000e+00
-  %add.2 = fadd float %in, 1.000000e+00
-  %sel.1 = select i1 %cmp1, float %add, float 1.000000e+00
-  %sel.2 = select i1 %cmp1, float 2.000000e+00, float %add.2
-  %res = fadd float %sel.1, %sel.2
-  ret float %res
+  %sel = select i1 %cmp1, float %add, float 1.000000e+00
+  ret float %sel
 }
 
-
-; Check for fmin scenarios that shouldn't be transformed.
-define float @test_fmin_neg1(float %in, float %in2) {
-; CHECK-LABEL: define float @test_fmin_neg1(
+; fcmp arg doesn't match with fadd's. This won't be converted to maxnum/minnum.
+define float @test_fcmp_fadd_arg_mismatch(float %in, float %in2) {
+; CHECK-LABEL: define float @test_fcmp_fadd_arg_mismatch(
 ; CHECK-SAME: float [[IN:%.*]], float [[IN2:%.*]]) {
-; CHECK-NEXT:    [[CMP1:%.*]] = fcmp olt float [[IN2]], 0.000000e+00
+; CHECK-NEXT:    [[CMP1:%.*]] = fcmp ogt float [[IN2]], 0.000000e+00
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[IN]], 1.000000e+00
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP1]], float [[ADD]], float 1.000000e+00
+; CHECK-NEXT:    [[SEL:%.*]] = select nnan nsz i1 [[CMP1]], float [[ADD]], float 1.000000e+00
 ; CHECK-NEXT:    ret float [[SEL]]
 ;
-  %cmp1 = fcmp olt float %in2, 0.000000e+00
+  %cmp1 = fcmp ogt float %in2, 0.000000e+00
   %add = fadd float %in, 1.000000e+00
-  %sel = select i1 %cmp1, float %add, float 1.000000e+00
+  %sel = select nnan nsz i1 %cmp1, float %add, float 1.000000e+00
   ret float %sel
 }
 
-define float @test_fmin_neg2(float %in) {
-; CHECK-LABEL: define float @test_fmin_neg2(
+; It won't be converted to maxnum/minnum because constant arg in fcmp isn't zero.
+define float @test_fcmp_arg_non_zero(float %in) {
+; CHECK-LABEL: define float @test_fcmp_arg_non_zero(
 ; CHECK-SAME: float [[IN:%.*]]) {
-; CHECK-NEXT:    [[CMP1:%.*]] = fcmp olt float [[IN]], 1.000000e+00
+; CHECK-NEXT:    [[CMP1:%.*]] = fcmp ogt float [[IN]], 1.000000e+00
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[IN]], 1.000000e+00
-; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP1]], float [[ADD]], float 1.000000e+00
+; CHECK-NEXT:    [[SEL:%.*]] = select nnan nsz i1 [[CMP1]], float [[ADD]], float 1.000000e+00
 ; CHECK-NEXT:    ret float [[SEL]]
 ;
-  %cmp1 = fcmp olt float %in, 1.000000e+00
+  %cmp1 = fcmp ogt float %in, 1.000000e+00
   %add = fadd float %in, 1.000000e+00
-  %sel = select i1 %cmp1, float %add, float 1.000000e+00
+  %sel = select nnan nsz i1 %cmp1, float %add, float 1.000000e+00
   ret float %sel
 }
 
-define float @test_fmin_neg3(float %in) {
-; CHECK-LABEL: define float @test_fmin_neg3(
+; fcmp has more than one use.
+define float @test_fcmp_multiple_uses(float %in) {
+; CHECK-LABEL: define float @test_fcmp_multiple_uses(
 ; CHECK-SAME: float [[IN:%.*]]) {
-; CHECK-NEXT:    [[CMP1:%.*]] = fcmp olt float [[IN]], 0.000000e+00
+; CHECK-NEXT:    [[CMP1:%.*]] = fcmp ogt float [[IN]], 0.000000e+00
 ; CHECK-NEXT:    [[ADD:%.*]] = fadd float [[IN]], 1.000000e+00
 ; CHECK-NEXT:    [[ADD_2:%.*]] = fadd float [[IN]], 1.000000e+00
-; CHECK-NEXT:    [[SEL_1:%.*]] = select i1 [[CMP1]], float [[ADD]], float 1.000000e+00
-; CHECK-NEXT:    [[SEL_2:%.*]] = select i1 [[CMP1]], float 2.000000e+00, float [[ADD_2]]
+; CHECK-NEXT:    [[SEL_1:%.*]] = select nnan nsz i1 [[CMP1]], float [[ADD]], float 1.000000e+00
+; CHECK-NEXT:    [[SEL_2:%.*]] = select nnan nsz i1 [[CMP1]], float 2.000000e+00, float [[ADD_2]]
 ; CHECK-NEXT:    [[RES:%.*]] = fadd float [[SEL_1]], [[SEL_2]]
 ; CHECK-NEXT:    ret float [[RES]]
 ;
-  %cmp1 = fcmp olt float %in, 0.000000e+00
+  %cmp1 = fcmp ogt float %in, 0.000000e+00
   %add = fadd float %in, 1.000000e+00
   %add.2 = fadd float %in, 1.000000e+00
-  %sel.1 = select i1 %cmp1, float %add, float 1.000000e+00
-  %sel.2 = select i1 %cmp1, float 2.000000e+00, float %add.2
+  %sel.1 = select nnan nsz i1 %cmp1, float %add, float 1.000000e+00
+  %sel.2 = select nnan nsz i1 %cmp1, float 2.000000e+00, float %add.2
   %res = fadd float %sel.1, %sel.2
   ret float %res
 }

>From 71d1be066891ac11467b4e150a795207fdae32cb Mon Sep 17 00:00:00 2001
From: rbajpai <rbajpai at nvidia.com>
Date: Mon, 30 Sep 2024 15:53:48 +0530
Subject: [PATCH 3/5] Addressed review comments.

---
 .../InstCombine/InstCombineSelect.cpp         | 26 +++++--------------
 1 file changed, 7 insertions(+), 19 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 7103b3c9e8cd30..7c292b81d51eac 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -3720,7 +3720,7 @@ static Value *foldSelectIntoAddConstant(SelectInst &SI,
 
   // Note: OneUse check for `Cmp` is necessary because it makes sure that other
   // InstCombine folds don't undo this transformation and cause an infinite
-  // loop.
+  // loop. Furthermore, it could also increase the operation count.
   if (match(&SI, m_Select(m_OneUse(m_FCmp(Pred, m_Value(X), m_Value(Z))),
                           m_OneUse(m_Instruction(FAdd)), m_Constant(C))) ||
       match(&SI, m_Select(m_OneUse(m_FCmp(Pred, m_Value(X), m_Value(Z))),
@@ -3728,31 +3728,19 @@ static Value *foldSelectIntoAddConstant(SelectInst &SI,
     if (!match(Z, m_AnyZeroFP()))
       return nullptr;
 
-    // Only these Predicates can be transformed into fmaxnum/fminnum intrinsic.
-    switch (Pred) {
-    default:
+    // Only these relational predicates can be transformed into maxnum/minnum
+    // intrinsic.
+    if (!CmpInst::isRelational(Pred))
       return nullptr;
-    case FCmpInst::FCMP_OGT:
-    case FCmpInst::FCMP_OGE:
-    case FCmpInst::FCMP_OLT:
-    case FCmpInst::FCMP_OLE:
-    case FCmpInst::FCMP_UGT:
-    case FCmpInst::FCMP_UGE:
-    case FCmpInst::FCMP_ULT:
-    case FCmpInst::FCMP_ULE:
-      break;
-    }
 
     if (!match(FAdd, m_FAdd(m_Specific(X), m_Specific(C))))
       return nullptr;
 
-    Value *NewSelect = Builder.CreateSelect(SI.getCondition(), X, Z,
-                                            SI.getName() + ".new", &SI);
+    Value *NewSelect =
+        Builder.CreateSelect(SI.getCondition(), X, Z, SI.getName(), &SI);
     cast<Instruction>(NewSelect)->setFastMathFlags(SI.getFastMathFlags());
 
-    Value *NewFAdd =
-        Builder.CreateFAddFMF(NewSelect, C, FAdd, FAdd->getName() + ".new");
-    return NewFAdd;
+    return Builder.CreateFAddFMF(NewSelect, C, FAdd, FAdd->getName());
   }
 
   return nullptr;

>From a86a72f5605e0d863c375d7be0e2f03e18ce566f Mon Sep 17 00:00:00 2001
From: rbajpai <rbajpai at nvidia.com>
Date: Fri, 4 Oct 2024 13:19:15 +0530
Subject: [PATCH 4/5] Added `takeName` calls to take name from existing
 instructions

---
 llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 7c292b81d51eac..64dbde11bbf3f5 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -3736,11 +3736,13 @@ static Value *foldSelectIntoAddConstant(SelectInst &SI,
     if (!match(FAdd, m_FAdd(m_Specific(X), m_Specific(C))))
       return nullptr;
 
-    Value *NewSelect =
-        Builder.CreateSelect(SI.getCondition(), X, Z, SI.getName(), &SI);
+    Value *NewSelect = Builder.CreateSelect(SI.getCondition(), X, Z, "", &SI);
     cast<Instruction>(NewSelect)->setFastMathFlags(SI.getFastMathFlags());
+    NewSelect->takeName(&SI);
 
-    return Builder.CreateFAddFMF(NewSelect, C, FAdd, FAdd->getName());
+    Value *NewFAdd = Builder.CreateFAddFMF(NewSelect, C, FAdd);
+    NewFAdd->takeName(FAdd);
+    return NewFAdd;
   }
 
   return nullptr;

>From 0f8eb7b842775eed04a2611def8c0817d5e41acc Mon Sep 17 00:00:00 2001
From: rbajpai <rbajpai at nvidia.com>
Date: Fri, 4 Oct 2024 13:25:01 +0530
Subject: [PATCH 5/5] Combine two if conditions into one.

---
 llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 64dbde11bbf3f5..adae040c5e51b9 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -3725,12 +3725,9 @@ static Value *foldSelectIntoAddConstant(SelectInst &SI,
                           m_OneUse(m_Instruction(FAdd)), m_Constant(C))) ||
       match(&SI, m_Select(m_OneUse(m_FCmp(Pred, m_Value(X), m_Value(Z))),
                           m_Constant(C), m_OneUse(m_Instruction(FAdd))))) {
-    if (!match(Z, m_AnyZeroFP()))
-      return nullptr;
-
     // Only these relational predicates can be transformed into maxnum/minnum
     // intrinsic.
-    if (!CmpInst::isRelational(Pred))
+    if (!CmpInst::isRelational(Pred) || !match(Z, m_AnyZeroFP()))
       return nullptr;
 
     if (!match(FAdd, m_FAdd(m_Specific(X), m_Specific(C))))



More information about the llvm-commits mailing list