Index: include/llvm/Analysis/ValueTracking.h =================================================================== --- include/llvm/Analysis/ValueTracking.h +++ include/llvm/Analysis/ValueTracking.h @@ -21,6 +21,7 @@ #include "llvm/IR/Constants.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Intrinsics.h" +#include "llvm/IR/Operator.h" #include #include @@ -541,6 +542,7 @@ SelectPatternFlavor Flavor; SelectPatternNaNBehavior NaNBehavior; /// Only applicable if Flavor is /// SPF_FMINNUM or SPF_FMAXNUM. + FastMathFlags FMF; /// Any inferred flags from the pattern. bool Ordered; /// When implementing this min/max pattern as /// fcmp; select, does the fcmp have to be /// ordered? Index: include/llvm/CodeGen/SelectionDAGNodes.h =================================================================== --- include/llvm/CodeGen/SelectionDAGNodes.h +++ include/llvm/CodeGen/SelectionDAGNodes.h @@ -378,15 +378,20 @@ AllowContract(false), ApproximateFuncs(false), AllowReassociation(false) {} + /// Propagate the fast-math-flags from IR FastMathFlags + void copyFMF(FastMathFlags FMF) { + setNoNaNs(FMF.noNaNs()); + setNoInfs(FMF.noInfs()); + setNoSignedZeros(FMF.noSignedZeros()); + setAllowReciprocal(FMF.allowReciprocal()); + setAllowContract(FMF.allowContract()); + setApproximateFuncs(FMF.approxFunc()); + setAllowReassociation(FMF.allowReassoc()); + } + /// Propagate the fast-math-flags from an IR FPMathOperator. void copyFMF(const FPMathOperator &FPMO) { - setNoNaNs(FPMO.hasNoNaNs()); - setNoInfs(FPMO.hasNoInfs()); - setNoSignedZeros(FPMO.hasNoSignedZeros()); - setAllowReciprocal(FPMO.hasAllowReciprocal()); - setAllowContract(FPMO.hasAllowContract()); - setApproximateFuncs(FPMO.hasApproxFunc()); - setAllowReassociation(FPMO.hasAllowReassoc()); + copyFMF(FPMO.getFastMathFlags()); } /// Sets the state of the flags to the defined state. Index: include/llvm/IR/Operator.h =================================================================== --- include/llvm/IR/Operator.h +++ include/llvm/IR/Operator.h @@ -233,6 +233,10 @@ void operator&=(const FastMathFlags &OtherFlags) { Flags &= OtherFlags.Flags; } + + bool operator==(const FastMathFlags OtherFlags) const { + return Flags == OtherFlags.Flags; + } }; /// Utility class for floating point operations which can have Index: lib/Analysis/ValueTracking.cpp =================================================================== --- lib/Analysis/ValueTracking.cpp +++ lib/Analysis/ValueTracking.cpp @@ -4383,7 +4383,8 @@ static SelectPatternResult matchFastFloatClamp(CmpInst::Predicate Pred, Value *CmpLHS, Value *CmpRHS, Value *TrueVal, Value *FalseVal, - Value *&LHS, Value *&RHS) { + Value *&LHS, Value *&RHS, + FastMathFlags FMF) { // Try to match // X < C1 ? C1 : Min(X, C2) --> Max(C1, Min(X, C2)) // X > C1 ? C1 : Max(X, C2) --> Min(C1, Max(X, C2)) @@ -4401,7 +4402,7 @@ const APFloat *FC1; if (CmpRHS != TrueVal || !match(CmpRHS, m_APFloat(FC1)) || !FC1->isFinite()) - return {SPF_UNKNOWN, SPNB_NA, false}; + return {SPF_UNKNOWN, SPNB_NA, FMF, false}; const APFloat *FC2; switch (Pred) { @@ -4413,7 +4414,7 @@ m_CombineOr(m_OrdFMin(m_Specific(CmpLHS), m_APFloat(FC2)), m_UnordFMin(m_Specific(CmpLHS), m_APFloat(FC2)))) && FC1->compare(*FC2) == APFloat::cmpResult::cmpLessThan) - return {SPF_FMAXNUM, SPNB_RETURNS_ANY, false}; + return {SPF_FMAXNUM, SPNB_RETURNS_ANY, FMF, false}; break; case CmpInst::FCMP_OGT: case CmpInst::FCMP_OGE: @@ -4423,13 +4424,13 @@ m_CombineOr(m_OrdFMax(m_Specific(CmpLHS), m_APFloat(FC2)), m_UnordFMax(m_Specific(CmpLHS), m_APFloat(FC2)))) && FC1->compare(*FC2) == APFloat::cmpResult::cmpGreaterThan) - return {SPF_FMINNUM, SPNB_RETURNS_ANY, false}; + return {SPF_FMINNUM, SPNB_RETURNS_ANY, FMF, false}; break; default: break; } - return {SPF_UNKNOWN, SPNB_NA, false}; + return {SPF_UNKNOWN, SPNB_NA, FastMathFlags(), false}; } /// Recognize variations of: @@ -4448,24 +4449,24 @@ // (X SMAX(SMIN(X, C2), C1) if (match(FalseVal, m_SMin(m_Specific(CmpLHS), m_APInt(C2))) && C1->slt(*C2) && Pred == CmpInst::ICMP_SLT) - return {SPF_SMAX, SPNB_NA, false}; + return {SPF_SMAX, SPNB_NA, FastMathFlags(), false}; // (X >s C1) ? C1 : SMAX(X, C2) ==> SMIN(SMAX(X, C2), C1) if (match(FalseVal, m_SMax(m_Specific(CmpLHS), m_APInt(C2))) && C1->sgt(*C2) && Pred == CmpInst::ICMP_SGT) - return {SPF_SMIN, SPNB_NA, false}; + return {SPF_SMIN, SPNB_NA, FastMathFlags(), false}; // (X UMAX(UMIN(X, C2), C1) if (match(FalseVal, m_UMin(m_Specific(CmpLHS), m_APInt(C2))) && C1->ult(*C2) && Pred == CmpInst::ICMP_ULT) - return {SPF_UMAX, SPNB_NA, false}; + return {SPF_UMAX, SPNB_NA, FastMathFlags(), false}; // (X >u C1) ? C1 : UMAX(X, C2) ==> UMIN(UMAX(X, C2), C1) if (match(FalseVal, m_UMax(m_Specific(CmpLHS), m_APInt(C2))) && C1->ugt(*C2) && Pred == CmpInst::ICMP_UGT) - return {SPF_UMIN, SPNB_NA, false}; + return {SPF_UMIN, SPNB_NA, FastMathFlags(), false}; } - return {SPF_UNKNOWN, SPNB_NA, false}; + return {SPF_UNKNOWN, SPNB_NA, FastMathFlags(), false}; } /// Recognize variations of: @@ -4480,12 +4481,12 @@ Value *A, *B; SelectPatternResult L = matchSelectPattern(TVal, A, B, nullptr, Depth + 1); if (!SelectPatternResult::isMinOrMax(L.Flavor)) - return {SPF_UNKNOWN, SPNB_NA, false}; + return {SPF_UNKNOWN, SPNB_NA, FastMathFlags(), false}; Value *C, *D; SelectPatternResult R = matchSelectPattern(FVal, C, D, nullptr, Depth + 1); if (L.Flavor != R.Flavor) - return {SPF_UNKNOWN, SPNB_NA, false}; + return {SPF_UNKNOWN, SPNB_NA, FastMathFlags(), false}; // We have something like: x Pred y ? min(a, b) : min(c, d). // Try to match the compare to the min/max operations of the select operands. @@ -4498,7 +4499,7 @@ } if (Pred == ICmpInst::ICMP_SLT || Pred == ICmpInst::ICMP_SLE) break; - return {SPF_UNKNOWN, SPNB_NA, false}; + return {SPF_UNKNOWN, SPNB_NA, FastMathFlags(), false}; case SPF_SMAX: if (Pred == ICmpInst::ICMP_SLT || Pred == ICmpInst::ICMP_SLE) { Pred = ICmpInst::getSwappedPredicate(Pred); @@ -4506,7 +4507,7 @@ } if (Pred == ICmpInst::ICMP_SGT || Pred == ICmpInst::ICMP_SGE) break; - return {SPF_UNKNOWN, SPNB_NA, false}; + return {SPF_UNKNOWN, SPNB_NA, FastMathFlags(), false}; case SPF_UMIN: if (Pred == ICmpInst::ICMP_UGT || Pred == ICmpInst::ICMP_UGE) { Pred = ICmpInst::getSwappedPredicate(Pred); @@ -4514,7 +4515,7 @@ } if (Pred == ICmpInst::ICMP_ULT || Pred == ICmpInst::ICMP_ULE) break; - return {SPF_UNKNOWN, SPNB_NA, false}; + return {SPF_UNKNOWN, SPNB_NA, FastMathFlags(), false}; case SPF_UMAX: if (Pred == ICmpInst::ICMP_ULT || Pred == ICmpInst::ICMP_ULE) { Pred = ICmpInst::getSwappedPredicate(Pred); @@ -4522,9 +4523,9 @@ } if (Pred == ICmpInst::ICMP_UGT || Pred == ICmpInst::ICMP_UGE) break; - return {SPF_UNKNOWN, SPNB_NA, false}; + return {SPF_UNKNOWN, SPNB_NA, FastMathFlags(), false}; default: - return {SPF_UNKNOWN, SPNB_NA, false}; + return {SPF_UNKNOWN, SPNB_NA, FastMathFlags(), false}; } // If there is a common operand in the already matched min/max and the other @@ -4536,31 +4537,31 @@ if (D == B) { if ((CmpLHS == A && CmpRHS == C) || (match(C, m_Not(m_Specific(CmpLHS))) && match(A, m_Not(m_Specific(CmpRHS))))) - return {L.Flavor, SPNB_NA, false}; + return {L.Flavor, SPNB_NA, FastMathFlags(), false}; } // a pred d ? m(a, b) : m(b, d) --> m(m(a, b), m(b, d)) // ~d pred ~a ? m(a, b) : m(b, d) --> m(m(a, b), m(b, d)) if (C == B) { if ((CmpLHS == A && CmpRHS == D) || (match(D, m_Not(m_Specific(CmpLHS))) && match(A, m_Not(m_Specific(CmpRHS))))) - return {L.Flavor, SPNB_NA, false}; + return {L.Flavor, SPNB_NA, FastMathFlags(), false}; } // b pred c ? m(a, b) : m(c, a) --> m(m(a, b), m(c, a)) // ~c pred ~b ? m(a, b) : m(c, a) --> m(m(a, b), m(c, a)) if (D == A) { if ((CmpLHS == B && CmpRHS == C) || (match(C, m_Not(m_Specific(CmpLHS))) && match(B, m_Not(m_Specific(CmpRHS))))) - return {L.Flavor, SPNB_NA, false}; + return {L.Flavor, SPNB_NA, FastMathFlags(), false}; } // b pred d ? m(a, b) : m(a, d) --> m(m(a, b), m(a, d)) // ~d pred ~b ? m(a, b) : m(a, d) --> m(m(a, b), m(a, d)) if (C == A) { if ((CmpLHS == B && CmpRHS == D) || (match(D, m_Not(m_Specific(CmpLHS))) && match(B, m_Not(m_Specific(CmpRHS))))) - return {L.Flavor, SPNB_NA, false}; + return {L.Flavor, SPNB_NA, FastMathFlags(), false}; } - return {SPF_UNKNOWN, SPNB_NA, false}; + return {SPF_UNKNOWN, SPNB_NA, FastMathFlags(), false}; } /// Match non-obvious integer minimum and maximum sequences. @@ -4582,25 +4583,27 @@ return SPR; if (Pred != CmpInst::ICMP_SGT && Pred != CmpInst::ICMP_SLT) - return {SPF_UNKNOWN, SPNB_NA, false}; + return {SPF_UNKNOWN, SPNB_NA, FastMathFlags(), false}; // Z = X -nsw Y // (X >s Y) ? 0 : Z ==> (Z >s 0) ? 0 : Z ==> SMIN(Z, 0) // (X (Z SMAX(Z, 0) if (match(TrueVal, m_Zero()) && match(FalseVal, m_NSWSub(m_Specific(CmpLHS), m_Specific(CmpRHS)))) - return {Pred == CmpInst::ICMP_SGT ? SPF_SMIN : SPF_SMAX, SPNB_NA, false}; + return {Pred == CmpInst::ICMP_SGT ? SPF_SMIN : SPF_SMAX, SPNB_NA, + FastMathFlags(), false}; // Z = X -nsw Y // (X >s Y) ? Z : 0 ==> (Z >s 0) ? Z : 0 ==> SMAX(Z, 0) // (X (Z SMIN(Z, 0) if (match(FalseVal, m_Zero()) && match(TrueVal, m_NSWSub(m_Specific(CmpLHS), m_Specific(CmpRHS)))) - return {Pred == CmpInst::ICMP_SGT ? SPF_SMAX : SPF_SMIN, SPNB_NA, false}; + return {Pred == CmpInst::ICMP_SGT ? SPF_SMAX : SPF_SMIN, SPNB_NA, + FastMathFlags(), false}; const APInt *C1; if (!match(CmpRHS, m_APInt(C1))) - return {SPF_UNKNOWN, SPNB_NA, false}; + return {SPF_UNKNOWN, SPNB_NA, FastMathFlags(), false}; // An unsigned min/max can be written with a signed compare. const APInt *C2; @@ -4611,14 +4614,16 @@ // (X (X >u MAXVAL) ? MAXVAL : X ==> UMIN if (Pred == CmpInst::ICMP_SLT && C1->isNullValue() && C2->isMaxSignedValue()) - return {CmpLHS == TrueVal ? SPF_UMAX : SPF_UMIN, SPNB_NA, false}; + return {CmpLHS == TrueVal ? SPF_UMAX : SPF_UMIN, SPNB_NA, + FastMathFlags(), false}; // Is the sign bit clear? // (X >s -1) ? MINVAL : X ==> (X UMAX // (X >s -1) ? X : MINVAL ==> (X UMIN if (Pred == CmpInst::ICMP_SGT && C1->isAllOnesValue() && C2->isMinSignedValue()) - return {CmpLHS == FalseVal ? SPF_UMAX : SPF_UMIN, SPNB_NA, false}; + return {CmpLHS == FalseVal ? SPF_UMAX : SPF_UMIN, SPNB_NA, + FastMathFlags(), false}; } // Look through 'not' ops to find disguised signed min/max. @@ -4626,15 +4631,17 @@ // (X (~X >s ~C) ? ~X : ~C ==> SMAX(~X, ~C) if (match(TrueVal, m_Not(m_Specific(CmpLHS))) && match(FalseVal, m_APInt(C2)) && ~(*C1) == *C2) - return {Pred == CmpInst::ICMP_SGT ? SPF_SMIN : SPF_SMAX, SPNB_NA, false}; + return {Pred == CmpInst::ICMP_SGT ? SPF_SMIN : SPF_SMAX, SPNB_NA, + FastMathFlags(), false}; // (X >s C) ? ~C : ~X ==> (~X SMAX(~C, ~X) // (X (~X >s ~C) ? ~C : ~X ==> SMIN(~C, ~X) if (match(FalseVal, m_Not(m_Specific(CmpLHS))) && match(TrueVal, m_APInt(C2)) && ~(*C1) == *C2) - return {Pred == CmpInst::ICMP_SGT ? SPF_SMAX : SPF_SMIN, SPNB_NA, false}; + return {Pred == CmpInst::ICMP_SGT ? SPF_SMAX : SPF_SMIN, SPNB_NA, + FastMathFlags(), false}; - return {SPF_UNKNOWN, SPNB_NA, false}; + return {SPF_UNKNOWN, SPNB_NA, FastMathFlags(), false}; } bool llvm::isKnownNegation(const Value *X, const Value *Y, bool NeedNSW) { @@ -4679,7 +4686,7 @@ case CmpInst::FCMP_UGE: case CmpInst::FCMP_ULE: if (!FMF.noSignedZeros() && !isKnownNonZero(CmpLHS) && !isKnownNonZero(CmpRHS)) - return {SPF_UNKNOWN, SPNB_NA, false}; + return {SPF_UNKNOWN, SPNB_NA, FastMathFlags(), false}; } SelectPatternNaNBehavior NaNBehavior = SPNB_NA; @@ -4708,7 +4715,7 @@ NaNBehavior = SPNB_RETURNS_OTHER; else // Completely unsafe. - return {SPF_UNKNOWN, SPNB_NA, false}; + return {SPF_UNKNOWN, SPNB_NA, FastMathFlags(), false}; } else { Ordered = false; // An unordered comparison will return true when given a NaN, so it @@ -4720,7 +4727,7 @@ NaNBehavior = SPNB_RETURNS_NAN; else // Completely unsafe. - return {SPF_UNKNOWN, SPNB_NA, false}; + return {SPF_UNKNOWN, SPNB_NA, FastMathFlags(), false}; } } @@ -4737,23 +4744,23 @@ // ([if]cmp X, Y) ? X : Y if (TrueVal == CmpLHS && FalseVal == CmpRHS) { switch (Pred) { - default: return {SPF_UNKNOWN, SPNB_NA, false}; // Equality. + default: return {SPF_UNKNOWN, SPNB_NA, FastMathFlags(), false}; // Equality. case ICmpInst::ICMP_UGT: - case ICmpInst::ICMP_UGE: return {SPF_UMAX, SPNB_NA, false}; + case ICmpInst::ICMP_UGE: return {SPF_UMAX, SPNB_NA, FastMathFlags(), false}; case ICmpInst::ICMP_SGT: - case ICmpInst::ICMP_SGE: return {SPF_SMAX, SPNB_NA, false}; + case ICmpInst::ICMP_SGE: return {SPF_SMAX, SPNB_NA, FastMathFlags(), false}; case ICmpInst::ICMP_ULT: - case ICmpInst::ICMP_ULE: return {SPF_UMIN, SPNB_NA, false}; + case ICmpInst::ICMP_ULE: return {SPF_UMIN, SPNB_NA, FastMathFlags(), false}; case ICmpInst::ICMP_SLT: - case ICmpInst::ICMP_SLE: return {SPF_SMIN, SPNB_NA, false}; + case ICmpInst::ICMP_SLE: return {SPF_SMIN, SPNB_NA, FastMathFlags(), false}; case FCmpInst::FCMP_UGT: case FCmpInst::FCMP_UGE: case FCmpInst::FCMP_OGT: - case FCmpInst::FCMP_OGE: return {SPF_FMAXNUM, NaNBehavior, Ordered}; + case FCmpInst::FCMP_OGE: return {SPF_FMAXNUM, NaNBehavior, FMF, Ordered}; case FCmpInst::FCMP_ULT: case FCmpInst::FCMP_ULE: case FCmpInst::FCMP_OLT: - case FCmpInst::FCMP_OLE: return {SPF_FMINNUM, NaNBehavior, Ordered}; + case FCmpInst::FCMP_OLE: return {SPF_FMINNUM, NaNBehavior, FMF, Ordered}; } } @@ -4775,12 +4782,12 @@ // (X >s 0) ? X : -X or (X >s -1) ? X : -X --> ABS(X) // (-X >s 0) ? -X : X or (-X >s -1) ? -X : X --> ABS(X) if (Pred == ICmpInst::ICMP_SGT && match(CmpRHS, ZeroOrAllOnes)) - return {SPF_ABS, SPNB_NA, false}; + return {SPF_ABS, SPNB_NA, FastMathFlags(), false}; // (X NABS(X) // (-X NABS(X) if (Pred == ICmpInst::ICMP_SLT && match(CmpRHS, ZeroOrOne)) - return {SPF_NABS, SPNB_NA, false}; + return {SPF_NABS, SPNB_NA, FastMathFlags(), false}; } else if (match(FalseVal, MaybeSExtCmpLHS)) { // Set the return values. If the compare uses the negated value (-X >s 0), @@ -4793,12 +4800,12 @@ // (X >s 0) ? -X : X or (X >s -1) ? -X : X --> NABS(X) // (-X >s 0) ? X : -X or (-X >s -1) ? X : -X --> NABS(X) if (Pred == ICmpInst::ICMP_SGT && match(CmpRHS, ZeroOrAllOnes)) - return {SPF_NABS, SPNB_NA, false}; + return {SPF_NABS, SPNB_NA, FastMathFlags(), false}; // (X ABS(X) // (-X ABS(X) if (Pred == ICmpInst::ICMP_SLT && match(CmpRHS, ZeroOrOne)) - return {SPF_ABS, SPNB_NA, false}; + return {SPF_ABS, SPNB_NA, FastMathFlags(), false}; } } @@ -4811,9 +4818,10 @@ if (NaNBehavior != SPNB_RETURNS_ANY || (!FMF.noSignedZeros() && !isKnownNonZero(CmpLHS) && !isKnownNonZero(CmpRHS))) - return {SPF_UNKNOWN, SPNB_NA, false}; + return {SPF_UNKNOWN, SPNB_NA, FastMathFlags(), false}; - return matchFastFloatClamp(Pred, CmpLHS, CmpRHS, TrueVal, FalseVal, LHS, RHS); + return matchFastFloatClamp(Pred, CmpLHS, CmpRHS, TrueVal, FalseVal, + LHS, RHS, FMF); } /// Helps to match a select pattern in case of a type mismatch. @@ -4927,13 +4935,13 @@ Instruction::CastOps *CastOp, unsigned Depth) { if (Depth >= MaxDepth) - return {SPF_UNKNOWN, SPNB_NA, false}; + return {SPF_UNKNOWN, SPNB_NA, FastMathFlags(), false}; SelectInst *SI = dyn_cast(V); - if (!SI) return {SPF_UNKNOWN, SPNB_NA, false}; + if (!SI) return {SPF_UNKNOWN, SPNB_NA, FastMathFlags(), false}; CmpInst *CmpI = dyn_cast(SI->getCondition()); - if (!CmpI) return {SPF_UNKNOWN, SPNB_NA, false}; + if (!CmpI) return {SPF_UNKNOWN, SPNB_NA, FastMathFlags(), false}; CmpInst::Predicate Pred = CmpI->getPredicate(); Value *CmpLHS = CmpI->getOperand(0); @@ -4946,7 +4954,7 @@ // Bail out early. if (CmpI->isEquality()) - return {SPF_UNKNOWN, SPNB_NA, false}; + return {SPF_UNKNOWN, SPNB_NA, FastMathFlags(), false}; // Deal with type mismatches. if (CastOp && CmpLHS->getType() != TrueVal->getType()) { Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -1085,8 +1085,10 @@ IncomingFlags.copyFMF(*FPMO); if (!Node->getFlags().isDefined()) Node->setFlags(IncomingFlags); +#if 0 else Node->intersectFlagsWith(IncomingFlags); +#endif } } @@ -2943,6 +2945,7 @@ auto BaseOps = {Cond}; ISD::NodeType OpCode = Cond.getValueType().isVector() ? ISD::VSELECT : ISD::SELECT; + SDNodeFlags Flags; // Min/max matching is only viable if all output VTs are the same. if (is_splat(ValueVTs)) { @@ -2964,6 +2967,8 @@ Value *LHS, *RHS; auto SPR = matchSelectPattern(const_cast(&I), LHS, RHS); + Flags.copyFMF(SPR.FMF); + ISD::NodeType Opc = ISD::DELETED_NODE; switch (SPR.Flavor) { case SPF_UMAX: Opc = ISD::UMAX; break; @@ -3028,7 +3033,7 @@ Ops.push_back(SDValue(RHSVal.getNode(), RHSVal.getResNo() + i)); Values[i] = DAG.getNode(OpCode, getCurSDLoc(), LHSVal.getNode()->getValueType(LHSVal.getResNo()+i), - Ops); + Ops, Flags); } setValue(&I, DAG.getNode(ISD::MERGE_VALUES, getCurSDLoc(), Index: unittests/Analysis/ValueTrackingTest.cpp =================================================================== --- unittests/Analysis/ValueTrackingTest.cpp +++ unittests/Analysis/ValueTrackingTest.cpp @@ -58,6 +58,7 @@ EXPECT_EQ(P.Flavor, R.Flavor); EXPECT_EQ(P.NaNBehavior, R.NaNBehavior); EXPECT_EQ(P.Ordered, R.Ordered); + EXPECT_EQ(P.FMF, R.FMF); } LLVMContext Context; @@ -74,7 +75,20 @@ " %A = select i1 %1, float %a, float 5.0\n" " ret float %A\n" "}\n"); - expectPattern({SPF_FMINNUM, SPNB_RETURNS_NAN, false}); + expectPattern({SPF_FMINNUM, SPNB_RETURNS_NAN, FastMathFlags(), false}); +} + +TEST_F(MatchSelectPatternTest, SimpleFMin_WithFMF) { + parseAssembly( + "define float @test(float %a) {\n" + " %1 = fcmp nsz ult float %a, 5.0\n" + " %A = select i1 %1, float %a, float 5.0\n" + " ret float %A\n" + "}\n"); + FastMathFlags FMF; + FMF.setNoSignedZeros(); + + expectPattern({SPF_FMINNUM, SPNB_RETURNS_NAN, FMF, false}); } TEST_F(MatchSelectPatternTest, SimpleFMax) { @@ -84,7 +98,7 @@ " %A = select i1 %1, float %a, float 5.0\n" " ret float %A\n" "}\n"); - expectPattern({SPF_FMAXNUM, SPNB_RETURNS_OTHER, true}); + expectPattern({SPF_FMAXNUM, SPNB_RETURNS_OTHER, FastMathFlags(), true}); } TEST_F(MatchSelectPatternTest, SwappedFMax) { @@ -94,7 +108,7 @@ " %A = select i1 %1, float %a, float 5.0\n" " ret float %A\n" "}\n"); - expectPattern({SPF_FMAXNUM, SPNB_RETURNS_OTHER, false}); + expectPattern({SPF_FMAXNUM, SPNB_RETURNS_OTHER, FastMathFlags(), false}); } TEST_F(MatchSelectPatternTest, SwappedFMax2) { @@ -104,7 +118,7 @@ " %A = select i1 %1, float 5.0, float %a\n" " ret float %A\n" "}\n"); - expectPattern({SPF_FMAXNUM, SPNB_RETURNS_NAN, false}); + expectPattern({SPF_FMAXNUM, SPNB_RETURNS_NAN, FastMathFlags(), false}); } TEST_F(MatchSelectPatternTest, SwappedFMax3) { @@ -114,7 +128,7 @@ " %A = select i1 %1, float 5.0, float %a\n" " ret float %A\n" "}\n"); - expectPattern({SPF_FMAXNUM, SPNB_RETURNS_OTHER, true}); + expectPattern({SPF_FMAXNUM, SPNB_RETURNS_OTHER, FastMathFlags(), true}); } TEST_F(MatchSelectPatternTest, FastFMin) { @@ -124,7 +138,9 @@ " %A = select i1 %1, float %a, float 5.0\n" " ret float %A\n" "}\n"); - expectPattern({SPF_FMINNUM, SPNB_RETURNS_ANY, false}); + FastMathFlags FMF; + FMF.setNoNaNs(); + expectPattern({SPF_FMINNUM, SPNB_RETURNS_ANY, FMF, false}); } TEST_F(MatchSelectPatternTest, FMinConstantZero) { @@ -135,7 +151,7 @@ " ret float %A\n" "}\n"); // This shouldn't be matched, as %a could be -0.0. - expectPattern({SPF_UNKNOWN, SPNB_NA, false}); + expectPattern({SPF_UNKNOWN, SPNB_NA, FastMathFlags(), false}); } TEST_F(MatchSelectPatternTest, FMinConstantZeroNsz) { @@ -145,8 +161,12 @@ " %A = select i1 %1, float %a, float 0.0\n" " ret float %A\n" "}\n"); + + FastMathFlags FMF; + FMF.setNoSignedZeros(); + // But this should be, because we've ignored signed zeroes. - expectPattern({SPF_FMINNUM, SPNB_RETURNS_OTHER, true}); + expectPattern({SPF_FMINNUM, SPNB_RETURNS_OTHER, FMF, true}); } TEST_F(MatchSelectPatternTest, DoubleCastU) { @@ -160,7 +180,7 @@ "}\n"); // We should be able to look through the situation where we cast both operands // to the select. - expectPattern({SPF_UMIN, SPNB_NA, false}); + expectPattern({SPF_UMIN, SPNB_NA, FastMathFlags(), false}); } TEST_F(MatchSelectPatternTest, DoubleCastS) { @@ -174,7 +194,7 @@ "}\n"); // We should be able to look through the situation where we cast both operands // to the select. - expectPattern({SPF_SMIN, SPNB_NA, false}); + expectPattern({SPF_SMIN, SPNB_NA, FastMathFlags(), false}); } TEST_F(MatchSelectPatternTest, DoubleCastBad) { @@ -187,7 +207,7 @@ " ret i32 %A\n" "}\n"); // The cast types here aren't the same, so we cannot match an UMIN. - expectPattern({SPF_UNKNOWN, SPNB_NA, false}); + expectPattern({SPF_UNKNOWN, SPNB_NA, FastMathFlags(), false}); } TEST(ValueTracking, GuaranteedToTransferExecutionToSuccessor) {