[PatternMatch] Add new FP matchers. NFC.
authorJay Foad <jay.foad@amd.com>
Fri, 16 Oct 2020 12:54:19 +0000 (13:54 +0100)
committerJay Foad <jay.foad@amd.com>
Thu, 22 Oct 2020 18:43:12 +0000 (19:43 +0100)
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

llvm/include/llvm/IR/PatternMatch.h
llvm/unittests/IR/PatternMatch.cpp

index 85a358f..987d9c4 100644 (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 {
index 97d8da5..86d9ed5 100644 (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});
+
+  Constant *VectorInfUndef = ConstantVector::get(
+      {ScalarPosInf, ScalarNegInf, ScalarUndef, ScalarPosInf});
 
-  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 *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) {