[llvm] [InstCombine] Transform (fcmp + fadd + sel) into (fcmp + sel + fadd) (PR #106492)
Rajat Bajpai via llvm-commits
llvm-commits at lists.llvm.org
Tue Oct 8 03:32:34 PDT 2024
https://github.com/rajatbajpai updated https://github.com/llvm/llvm-project/pull/106492
>From 5cd438e422de3be3662e3f4f93d3843e54a6c44a 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/6] [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 e22a8c7cf5d460ef3f8806d68f3fe490c5367d14 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/6] 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 944e04fbbe37f0129319de15f7846b073a12809a 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/6] 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 da9700954ed9646492d30d014562d2a7f1f17517 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/6] 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 ade6ca988a04add1ea3eff379b5230c8c8c4f6d5 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/6] 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))))
>From 301cc8c7d021b4dcdcdd8009ace11f76056f05fd Mon Sep 17 00:00:00 2001
From: rbajpai <rbajpai at nvidia.com>
Date: Tue, 8 Oct 2024 15:51:55 +0530
Subject: [PATCH 6/6] Added intersection of rewrite-based flags.
---
.../InstCombine/InstCombineSelect.cpp | 29 +++++++++++++++++--
.../InstCombine/fcmp-fadd-select.ll | 27 +++++++++++++++++
2 files changed, 54 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index adae040c5e51b9..b3083edd7a6766 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -3734,11 +3734,36 @@ static Value *foldSelectIntoAddConstant(SelectInst &SI,
return nullptr;
Value *NewSelect = Builder.CreateSelect(SI.getCondition(), X, Z, "", &SI);
- cast<Instruction>(NewSelect)->setFastMathFlags(SI.getFastMathFlags());
NewSelect->takeName(&SI);
- Value *NewFAdd = Builder.CreateFAddFMF(NewSelect, C, FAdd);
+ Value *NewFAdd = Builder.CreateFAdd(NewSelect, C);
NewFAdd->takeName(FAdd);
+
+ // Propagate rewrite-based flags
+ auto SelectFMF = SI.getFastMathFlags();
+ auto FAddFMF = FAdd->getFastMathFlags();
+ FastMathFlags CommonFMF, NewFAddFMF, NewSelectFMF;
+
+ CommonFMF.setAllowReassoc(SelectFMF.allowReassoc() &&
+ FAddFMF.allowReassoc());
+ CommonFMF.setAllowReciprocal(SelectFMF.allowReciprocal() &&
+ FAddFMF.allowReciprocal());
+ CommonFMF.setAllowContract(SelectFMF.allowContract() &&
+ FAddFMF.allowContract());
+ CommonFMF.setApproxFunc(SelectFMF.approxFunc() && FAddFMF.approxFunc());
+ NewSelectFMF = NewFAddFMF = CommonFMF;
+
+ // Propagate FastMath flags
+ NewFAddFMF.setNoNaNs(FAddFMF.noNaNs());
+ NewFAddFMF.setNoInfs(FAddFMF.noInfs());
+ NewFAddFMF.setNoSignedZeros(FAddFMF.noSignedZeros());
+ cast<Instruction>(NewFAdd)->setFastMathFlags(NewFAddFMF);
+
+ NewSelectFMF.setNoNaNs(SelectFMF.noNaNs());
+ NewSelectFMF.setNoInfs(SelectFMF.noInfs());
+ NewSelectFMF.setNoSignedZeros(SelectFMF.noSignedZeros());
+ cast<Instruction>(NewSelect)->setFastMathFlags(NewSelectFMF);
+
return NewFAdd;
}
diff --git a/llvm/test/Transforms/InstCombine/fcmp-fadd-select.ll b/llvm/test/Transforms/InstCombine/fcmp-fadd-select.ll
index b9717f78c79ab7..dd6ee8197cdabf 100644
--- a/llvm/test/Transforms/InstCombine/fcmp-fadd-select.ll
+++ b/llvm/test/Transforms/InstCombine/fcmp-fadd-select.ll
@@ -632,3 +632,30 @@ define float @test_fcmp_multiple_uses(float %in) {
%res = fadd float %sel.1, %sel.2
ret float %res
}
+
+; Rewrite-based flags propagation
+define float @test_fcmp_ogt_fadd_select_rewrite_flags(float %in) {
+; CHECK-LABEL: define float @test_fcmp_ogt_fadd_select_rewrite_flags(
+; CHECK-SAME: float [[IN:%.*]]) {
+; CHECK-NEXT: [[SEL_NEW:%.*]] = call reassoc nnan nsz arcp contract afn float @llvm.maxnum.f32(float [[IN]], float 0.000000e+00)
+; CHECK-NEXT: [[ADD_NEW:%.*]] = fadd reassoc arcp contract afn float [[SEL_NEW]], 1.000000e+00
+; CHECK-NEXT: ret float [[ADD_NEW]]
+;
+ %cmp1 = fcmp ogt float %in, 0.000000e+00
+ %add = fadd reassoc afn arcp contract float %in, 1.000000e+00
+ %sel = select nnan nsz reassoc afn arcp contract i1 %cmp1, float %add, float 1.000000e+00
+ ret float %sel
+}
+
+define float @test_fcmp_ogt_fadd_select_rewrite_and_fastmath(float %in) {
+; CHECK-LABEL: define float @test_fcmp_ogt_fadd_select_rewrite_and_fastmath(
+; CHECK-SAME: float [[IN:%.*]]) {
+; CHECK-NEXT: [[SEL_NEW:%.*]] = call fast float @llvm.maxnum.f32(float [[IN]], float 0.000000e+00)
+; CHECK-NEXT: [[ADD_NEW:%.*]] = fadd fast float [[SEL_NEW]], 1.000000e+00
+; CHECK-NEXT: ret float [[ADD_NEW]]
+;
+ %cmp1 = fcmp ogt float %in, 0.000000e+00
+ %add = fadd fast float %in, 1.000000e+00
+ %sel = select fast i1 %cmp1, float %add, float 1.000000e+00
+ ret float %sel
+}
More information about the llvm-commits
mailing list