diff --git a/llvm/include/llvm/IR/FMF.h b/llvm/include/llvm/IR/FMF.h index f063060567db2..d204d0a0e9d9a 100644 --- a/llvm/include/llvm/IR/FMF.h +++ b/llvm/include/llvm/IR/FMF.h @@ -108,6 +108,20 @@ class FastMathFlags { /// Print fast-math flags to \p O. void print(raw_ostream &O) const; + + /// Intersect rewrite-based flags + static inline FastMathFlags intersectRewrite(FastMathFlags LHS, + FastMathFlags RHS) { + const unsigned RewriteMask = + AllowReassoc | AllowReciprocal | AllowContract | ApproxFunc; + return FastMathFlags(RewriteMask & LHS.Flags & RHS.Flags); + } + + /// Union value flags + static inline FastMathFlags unionValue(FastMathFlags LHS, FastMathFlags RHS) { + const unsigned ValueMask = NoNaNs | NoInfs | NoSignedZeros; + return FastMathFlags(ValueMask & (LHS.Flags | RHS.Flags)); + } }; inline FastMathFlags operator|(FastMathFlags LHS, FastMathFlags RHS) { diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp index c5f39a4c381ed..df08050aa4abd 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -3640,6 +3640,60 @@ static bool hasAffectedValue(Value *V, SmallPtrSetImpl &Affected, return false; } +// 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(&SI); + if (!SIFOp || !SIFOp->hasNoSignedZeros() || !SIFOp->hasNoNaNs()) + return nullptr; + + // 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; + + // 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. 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))), + m_Constant(C), m_OneUse(m_Instruction(FAdd))))) { + // Only these relational predicates can be transformed into maxnum/minnum + // intrinsic. + if (!CmpInst::isRelational(Pred) || !match(Z, m_AnyZeroFP())) + return nullptr; + + if (!match(FAdd, m_FAdd(m_Specific(X), m_Specific(C)))) + return nullptr; + + Value *NewSelect = Builder.CreateSelect(SI.getCondition(), X, Z, "", &SI); + NewSelect->takeName(&SI); + + Value *NewFAdd = Builder.CreateFAdd(NewSelect, C); + NewFAdd->takeName(FAdd); + + // Propagate FastMath flags + FastMathFlags SelectFMF = SI.getFastMathFlags(); + FastMathFlags FAddFMF = FAdd->getFastMathFlags(); + FastMathFlags NewFMF = FastMathFlags::intersectRewrite(SelectFMF, FAddFMF) | + FastMathFlags::unionValue(SelectFMF, FAddFMF); + cast(NewFAdd)->setFastMathFlags(NewFMF); + cast(NewSelect)->setFastMathFlags(NewFMF); + + return NewFAdd; + } + + return nullptr; +} + Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) { Value *CondVal = SI.getCondition(); Value *TrueVal = SI.getTrueValue(); @@ -4036,6 +4090,9 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) { if (Value *V = foldRoundUpIntegerWithPow2Alignment(SI, Builder)) return replaceInstUsesWith(SI, V); + 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() 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 0000000000000..9f9cf7a633c87 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/fcmp-fadd-select.ll @@ -0,0 +1,674 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt < %s -passes=instcombine -S | FileCheck %s + +; 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: [[SEL_NEW:%.*]] = call nnan nsz float @llvm.maxnum.f32(float [[IN]], float 0.000000e+00) +; CHECK-NEXT: [[ADD_NEW:%.*]] = fadd nnan nsz 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 nnan nsz i1 %cmp1, float %add, float 1.000000e+00 + ret float %sel +} + +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: [[SEL_NEW:%.*]] = call nnan nsz float @llvm.maxnum.f32(float [[IN]], float 0.000000e+00) +; CHECK-NEXT: [[ADD_NEW:%.*]] = fadd nnan nsz 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 nnan nsz i1 %cmp1, float 1.000000e+00, float %add + ret float %sel +} + +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: [[SEL_NEW:%.*]] = call nnan nsz float @llvm.maxnum.f32(float [[IN]], float 0.000000e+00) +; CHECK-NEXT: [[ADD_NEW:%.*]] = fadd nnan nsz 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 nnan nsz i1 %cmp1, float %add, float 1.000000e+00 + ret float %sel +} + +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: [[SEL_NEW:%.*]] = call nnan nsz float @llvm.maxnum.f32(float [[IN]], float 0.000000e+00) +; CHECK-NEXT: [[ADD_NEW:%.*]] = fadd nnan nsz float [[SEL_NEW]], 1.000000e+00 +; CHECK-NEXT: ret float [[ADD_NEW]] +; + %cmp1 = fcmp ogt 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_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 nnan nsz <2 x float> [[SEL_NEW]], +; CHECK-NEXT: ret <2 x float> [[ADD_NEW]] +; + %cmp1 = fcmp ogt <2 x float> %in, + %add = fadd <2 x float> %in, + %sel = select nnan nsz <2 x i1> %cmp1, <2 x float> %add, <2 x float> + 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: [[SEL_NEW:%.*]] = call nnan nsz float @llvm.minnum.f32(float [[IN]], float 0.000000e+00) +; CHECK-NEXT: [[ADD_NEW:%.*]] = fadd nnan nsz 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_constant_swapped(float %in) { +; CHECK-LABEL: define float @test_fcmp_olt_fadd_select_constant_swapped( +; 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 nsz 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 1.000000e+00, float %add + ret float %sel +} + +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: [[SEL_NEW:%.*]] = call nnan nsz float @llvm.minnum.f32(float [[IN]], float 0.000000e+00) +; CHECK-NEXT: [[ADD_NEW:%.*]] = fadd nnan nsz 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 nsz 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 nnan nsz <2 x float> [[SEL_NEW]], +; CHECK-NEXT: ret <2 x float> [[ADD_NEW]] +; + %cmp1 = fcmp olt <2 x float> %in, + %add = fadd <2 x float> %in, + %sel = select nnan nsz <2 x i1> %cmp1, <2 x float> %add, <2 x float> + 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 nnan nsz 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 nnan nsz i1 %cmp1, float %add, float 1.000000e+00 + ret float %sel +} + +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: [[SEL_NEW:%.*]] = call nnan nsz float @llvm.maxnum.f32(float [[IN]], float 0.000000e+00) +; CHECK-NEXT: [[ADD_NEW:%.*]] = fadd nnan nsz 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 nnan nsz i1 %cmp1, float 1.000000e+00, float %add + ret float %sel +} + +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: [[SEL_NEW:%.*]] = call nnan nsz float @llvm.maxnum.f32(float [[IN]], float 0.000000e+00) +; CHECK-NEXT: [[ADD_NEW:%.*]] = fadd nnan nsz 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 nnan nsz i1 %cmp1, float %add, float 1.000000e+00 + ret float %sel +} + +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: [[SEL_NEW:%.*]] = call nnan nsz float @llvm.maxnum.f32(float [[IN]], float 0.000000e+00) +; CHECK-NEXT: [[ADD_NEW:%.*]] = fadd nnan nsz float [[SEL_NEW]], 1.000000e+00 +; CHECK-NEXT: ret float [[ADD_NEW]] +; + %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 nnan nsz <2 x float> [[SEL_NEW]], +; CHECK-NEXT: ret <2 x float> [[ADD_NEW]] +; + %cmp1 = fcmp oge <2 x float> %in, + %add = fadd <2 x float> %in, + %sel = select nnan nsz <2 x i1> %cmp1, <2 x float> %add, <2 x float> + ret <2 x 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 nnan nsz 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_constant_swapped(float %in) { +; CHECK-LABEL: define float @test_fcmp_ole_fadd_select_constant_swapped( +; 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 nsz 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 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 nnan nsz 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 nsz 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 nnan nsz <2 x float> [[SEL_NEW]], +; CHECK-NEXT: ret <2 x float> [[ADD_NEW]] +; + %cmp1 = fcmp ole <2 x float> %in, + %add = fadd <2 x float> %in, + %sel = select nnan nsz <2 x i1> %cmp1, <2 x float> %add, <2 x float> + 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 nnan nsz 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 nnan nsz 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 nnan nsz 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 nsz 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 nnan nsz <2 x float> [[SEL_NEW]], +; CHECK-NEXT: ret <2 x float> [[ADD_NEW]] +; + %cmp1 = fcmp ugt <2 x float> %in, + %add = fadd <2 x float> %in, + %sel = select nnan nsz <2 x i1> %cmp1, <2 x float> %add, <2 x float> + 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 nnan nsz 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 nnan nsz 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 nnan nsz 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_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 nsz 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 nnan nsz <2 x float> [[SEL_NEW]], +; CHECK-NEXT: ret <2 x float> [[ADD_NEW]] +; + %cmp1 = fcmp uge <2 x float> %in, + %add = fadd <2 x float> %in, + %sel = select nnan nsz <2 x i1> %cmp1, <2 x float> %add, <2 x float> + 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 nnan nsz 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 nnan nsz 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 nnan nsz 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 nsz 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 nnan nsz <2 x float> [[SEL_NEW]], +; CHECK-NEXT: ret <2 x float> [[ADD_NEW]] +; + %cmp1 = fcmp ult <2 x float> %in, + %add = fadd <2 x float> %in, + %sel = select nnan nsz <2 x i1> %cmp1, <2 x float> %add, <2 x float> + 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 nnan nsz 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 nnan nsz 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 nnan nsz 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 nsz 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 nnan nsz <2 x float> [[SEL_NEW]], +; CHECK-NEXT: ret <2 x float> [[ADD_NEW]] +; + %cmp1 = fcmp ule <2 x float> %in, + %add = fadd <2 x float> %in, + %sel = select nnan nsz <2 x i1> %cmp1, <2 x float> %add, <2 x float> + 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: [[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 + %sel = select i1 %cmp1, float %add, float 1.000000e+00 + ret float %sel +} + +; 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 ogt float [[IN2]], 0.000000e+00 +; CHECK-NEXT: [[ADD:%.*]] = fadd float [[IN]], 1.000000e+00 +; CHECK-NEXT: [[SEL:%.*]] = select nnan nsz 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 nnan nsz i1 %cmp1, float %add, float 1.000000e+00 + ret float %sel +} + +; 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 ogt float [[IN]], 1.000000e+00 +; CHECK-NEXT: [[ADD:%.*]] = fadd float [[IN]], 1.000000e+00 +; CHECK-NEXT: [[SEL:%.*]] = select nnan nsz 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 nnan nsz i1 %cmp1, float %add, float 1.000000e+00 + ret float %sel +} + +; 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 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 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 ogt float %in, 0.000000e+00 + %add = fadd float %in, 1.000000e+00 + %add.2 = fadd float %in, 1.000000e+00 + %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 +} + +; Rewrite-based flags propagation +define float @test_fcmp_ogt_fadd_select_rewrite_flags1(float %in) { +; CHECK-LABEL: define float @test_fcmp_ogt_fadd_select_rewrite_flags1( +; 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 nnan nsz 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_flags2(float %in) { +; CHECK-LABEL: define float @test_fcmp_ogt_fadd_select_rewrite_flags2( +; 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 nnan nsz float [[SEL_NEW]], 1.000000e+00 +; CHECK-NEXT: ret float [[ADD_NEW]] +; + %cmp1 = fcmp ogt float %in, 0.000000e+00 + %add = fadd reassoc float %in, 1.000000e+00 + %sel = select nnan nsz 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 reassoc float %in, 1.000000e+00 + %sel = select fast i1 %cmp1, float %add, float 1.000000e+00 + ret float %sel +}