1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 18:54:02 +01:00

[PatternMatch] Add new FP matchers. NFC.

This adds matchers m_NonNaN, m_NonInf, m_Finite and m_NonZeroFP as well
as generic support for binding the matched value to an APFloat.

I tried to follow the existing convention of using an FP suffix for
predicates like zero and non-zero, which could be confused with the
integer versions, but not for predicates which are clearly already
FP-specific.

Differential Revision: https://reviews.llvm.org/D89038
This commit is contained in:
Jay Foad 2020-10-16 13:54:19 +01:00
parent 2c68bc5043
commit f8c9e8db39
2 changed files with 117 additions and 12 deletions

View File

@ -335,6 +335,33 @@ template <typename Predicate> struct api_pred_ty : public Predicate {
}
};
/// 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 <typename Predicate> struct apf_pred_ty : public Predicate {
const APFloat *&Res;
apf_pred_ty(const APFloat *&R) : Res(R) {}
template <typename ITy> bool match(ITy *V) {
if (const auto *CI = dyn_cast<ConstantFP>(V))
if (this->isValue(CI->getValue())) {
Res = &CI->getValue();
return true;
}
if (V->getType()->isVectorTy())
if (const auto *C = dyn_cast<Constant>(V))
if (auto *CI = dyn_cast_or_null<ConstantFP>(
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 @@ inline cstfp_pred_ty<is_nan> m_NaN() {
return cstfp_pred_ty<is_nan>();
}
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<is_nonnan> m_NonNaN() {
return cstfp_pred_ty<is_nonnan>();
}
struct is_inf {
bool isValue(const APFloat &C) { return C.isInfinity(); }
};
@ -564,6 +600,25 @@ inline cstfp_pred_ty<is_inf> m_Inf() {
return cstfp_pred_ty<is_inf>();
}
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<is_noninf> m_NonInf() {
return cstfp_pred_ty<is_noninf>();
}
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<is_finite> m_Finite() {
return cstfp_pred_ty<is_finite>();
}
inline apf_pred_ty<is_finite> m_Finite(const APFloat *&V) { return V; }
struct is_any_zero_fp {
bool isValue(const APFloat &C) { return C.isZero(); }
};
@ -591,6 +646,15 @@ inline cstfp_pred_ty<is_neg_zero_fp> m_NegZeroFP() {
return cstfp_pred_ty<is_neg_zero_fp>();
}
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<is_non_zero_fp> m_NonZeroFP() {
return cstfp_pred_ty<is_non_zero_fp>();
}
///////////////////////////////////////////////////////////////////////////////
template <typename Class> struct bind_ty {

View File

@ -1093,39 +1093,77 @@ TEST_F(PatternMatchTest, VectorUndefFloat) {
Constant *VectorZero = Constant::getNullValue(VectorTy);
Constant *ScalarPosInf = ConstantFP::getInfinity(ScalarTy, false);
Constant *ScalarNegInf = ConstantFP::getInfinity(ScalarTy, true);
Constant *ScalarNaN = ConstantFP::getNaN(ScalarTy, true);
SmallVector<Constant *, 4> 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});
SmallVector<Constant *, 4> InfElems;
InfElems.push_back(ScalarPosInf);
InfElems.push_back(ScalarNegInf);
InfElems.push_back(ScalarUndef);
InfElems.push_back(ScalarPosInf);
Constant *VectorInfUndef = ConstantVector::get(InfElems);
Constant *VectorInfUndef = ConstantVector::get(
{ScalarPosInf, ScalarNegInf, ScalarUndef, ScalarPosInf});
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 @@ TEST_F(PatternMatchTest, VectorUndefFloat) {
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) {