diff --git a/llvm/include/llvm/IR/PatternMatch.h b/llvm/include/llvm/IR/PatternMatch.h --- a/llvm/include/llvm/IR/PatternMatch.h +++ b/llvm/include/llvm/IR/PatternMatch.h @@ -335,6 +335,33 @@ } }; +/// This helper class is used to match scalar and vector constants that +/// satisfy a specified predicate, and bind them to an APFloat. +/// Undefs are allowed in splat vector constants. +template struct apf_pred_ty : public Predicate { + const APFloat *&Res; + + apf_pred_ty(const APFloat *&R) : Res(R) {} + + template bool match(ITy *V) { + if (const auto *CI = dyn_cast(V)) + if (this->isValue(CI->getValue())) { + Res = &CI->getValue(); + return true; + } + if (V->getType()->isVectorTy()) + if (const auto *C = dyn_cast(V)) + if (auto *CI = dyn_cast_or_null( + C->getSplatValue(/* AllowUndef */ true))) + if (this->isValue(CI->getValue())) { + Res = &CI->getValue(); + return true; + } + + return false; + } +}; + /////////////////////////////////////////////////////////////////////////////// // // Encapsulate constant value queries for use in templated predicate matchers. @@ -555,6 +582,15 @@ return cstfp_pred_ty(); } +struct is_nonnan { + bool isValue(const APFloat &C) { return !C.isNaN(); } +}; +/// Match a non-NaN FP constant. +/// For vectors, this includes constants with undefined elements. +inline cstfp_pred_ty m_NonNaN() { + return cstfp_pred_ty(); +} + struct is_inf { bool isValue(const APFloat &C) { return C.isInfinity(); } }; @@ -564,6 +600,25 @@ return cstfp_pred_ty(); } +struct is_noninf { + bool isValue(const APFloat &C) { return !C.isInfinity(); } +}; +/// Match a non-infinity FP constant, i.e. finite or NaN. +/// For vectors, this includes constants with undefined elements. +inline cstfp_pred_ty m_NonInf() { + return cstfp_pred_ty(); +} + +struct is_finite { + bool isValue(const APFloat &C) { return C.isFinite(); } +}; +/// Match a finite FP constant, i.e. not infinity or NaN. +/// For vectors, this includes constants with undefined elements. +inline cstfp_pred_ty m_Finite() { + return cstfp_pred_ty(); +} +inline apf_pred_ty m_Finite(const APFloat *&V) { return V; } + struct is_any_zero_fp { bool isValue(const APFloat &C) { return C.isZero(); } }; @@ -591,6 +646,15 @@ return cstfp_pred_ty(); } +struct is_non_zero_fp { + bool isValue(const APFloat &C) { return C.isNonZero(); } +}; +/// Match a floating-point non-zero. +/// For vectors, this includes constants with undefined elements. +inline cstfp_pred_ty m_NonZeroFP() { + return cstfp_pred_ty(); +} + /////////////////////////////////////////////////////////////////////////////// template struct bind_ty { diff --git a/llvm/unittests/IR/PatternMatch.cpp b/llvm/unittests/IR/PatternMatch.cpp --- a/llvm/unittests/IR/PatternMatch.cpp +++ b/llvm/unittests/IR/PatternMatch.cpp @@ -1093,39 +1093,77 @@ Constant *VectorZero = Constant::getNullValue(VectorTy); Constant *ScalarPosInf = ConstantFP::getInfinity(ScalarTy, false); Constant *ScalarNegInf = ConstantFP::getInfinity(ScalarTy, true); + Constant *ScalarNaN = ConstantFP::getNaN(ScalarTy, true); - SmallVector Elems; - Elems.push_back(ScalarUndef); - Elems.push_back(ScalarZero); - Elems.push_back(ScalarUndef); - Elems.push_back(ScalarZero); - Constant *VectorZeroUndef = ConstantVector::get(Elems); + Constant *VectorZeroUndef = + ConstantVector::get({ScalarUndef, ScalarZero, ScalarUndef, ScalarZero}); + + Constant *VectorInfUndef = ConstantVector::get( + {ScalarPosInf, ScalarNegInf, ScalarUndef, ScalarPosInf}); - SmallVector InfElems; - InfElems.push_back(ScalarPosInf); - InfElems.push_back(ScalarNegInf); - InfElems.push_back(ScalarUndef); - InfElems.push_back(ScalarPosInf); - Constant *VectorInfUndef = ConstantVector::get(InfElems); + Constant *VectorNaNUndef = + ConstantVector::get({ScalarUndef, ScalarNaN, ScalarNaN, ScalarNaN}); EXPECT_TRUE(match(ScalarUndef, m_Undef())); EXPECT_TRUE(match(VectorUndef, m_Undef())); EXPECT_FALSE(match(ScalarZero, m_Undef())); EXPECT_FALSE(match(VectorZero, m_Undef())); EXPECT_FALSE(match(VectorZeroUndef, m_Undef())); + EXPECT_FALSE(match(VectorInfUndef, m_Undef())); + EXPECT_FALSE(match(VectorNaNUndef, m_Undef())); EXPECT_FALSE(match(ScalarUndef, m_AnyZeroFP())); EXPECT_FALSE(match(VectorUndef, m_AnyZeroFP())); EXPECT_TRUE(match(ScalarZero, m_AnyZeroFP())); EXPECT_TRUE(match(VectorZero, m_AnyZeroFP())); EXPECT_TRUE(match(VectorZeroUndef, m_AnyZeroFP())); + EXPECT_FALSE(match(VectorInfUndef, m_AnyZeroFP())); + EXPECT_FALSE(match(VectorNaNUndef, m_AnyZeroFP())); + + EXPECT_FALSE(match(ScalarUndef, m_NaN())); + EXPECT_FALSE(match(VectorUndef, m_NaN())); + EXPECT_FALSE(match(VectorZeroUndef, m_NaN())); + EXPECT_FALSE(match(ScalarPosInf, m_NaN())); + EXPECT_FALSE(match(ScalarNegInf, m_NaN())); + EXPECT_TRUE(match(ScalarNaN, m_NaN())); + EXPECT_FALSE(match(VectorInfUndef, m_NaN())); + EXPECT_TRUE(match(VectorNaNUndef, m_NaN())); + + EXPECT_FALSE(match(ScalarUndef, m_NonNaN())); + EXPECT_FALSE(match(VectorUndef, m_NonNaN())); + EXPECT_TRUE(match(VectorZeroUndef, m_NonNaN())); + EXPECT_TRUE(match(ScalarPosInf, m_NonNaN())); + EXPECT_TRUE(match(ScalarNegInf, m_NonNaN())); + EXPECT_FALSE(match(ScalarNaN, m_NonNaN())); + EXPECT_TRUE(match(VectorInfUndef, m_NonNaN())); + EXPECT_FALSE(match(VectorNaNUndef, m_NonNaN())); EXPECT_FALSE(match(ScalarUndef, m_Inf())); EXPECT_FALSE(match(VectorUndef, m_Inf())); EXPECT_FALSE(match(VectorZeroUndef, m_Inf())); EXPECT_TRUE(match(ScalarPosInf, m_Inf())); EXPECT_TRUE(match(ScalarNegInf, m_Inf())); + EXPECT_FALSE(match(ScalarNaN, m_Inf())); EXPECT_TRUE(match(VectorInfUndef, m_Inf())); + EXPECT_FALSE(match(VectorNaNUndef, m_Inf())); + + EXPECT_FALSE(match(ScalarUndef, m_NonInf())); + EXPECT_FALSE(match(VectorUndef, m_NonInf())); + EXPECT_TRUE(match(VectorZeroUndef, m_NonInf())); + EXPECT_FALSE(match(ScalarPosInf, m_NonInf())); + EXPECT_FALSE(match(ScalarNegInf, m_NonInf())); + EXPECT_TRUE(match(ScalarNaN, m_NonInf())); + EXPECT_FALSE(match(VectorInfUndef, m_NonInf())); + EXPECT_TRUE(match(VectorNaNUndef, m_NonInf())); + + EXPECT_FALSE(match(ScalarUndef, m_Finite())); + EXPECT_FALSE(match(VectorUndef, m_Finite())); + EXPECT_TRUE(match(VectorZeroUndef, m_Finite())); + EXPECT_FALSE(match(ScalarPosInf, m_Finite())); + EXPECT_FALSE(match(ScalarNegInf, m_Finite())); + EXPECT_FALSE(match(ScalarNaN, m_Finite())); + EXPECT_FALSE(match(VectorInfUndef, m_Finite())); + EXPECT_FALSE(match(VectorNaNUndef, m_Finite())); const APFloat *C; // Regardless of whether undefs are allowed, @@ -1163,6 +1201,9 @@ C = nullptr; EXPECT_TRUE(match(VectorZeroUndef, m_APFloatAllowUndef(C))); EXPECT_TRUE(C->isZero()); + C = nullptr; + EXPECT_TRUE(match(VectorZeroUndef, m_Finite(C))); + EXPECT_TRUE(C->isZero()); } TEST_F(PatternMatchTest, FloatingPointFNeg) {