[llvm] ed80c86 - [PatternMatch] Add m_APInt/m_APFloat matchers accepting undef

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Wed Jan 22 13:49:59 PST 2020


Author: Nikita Popov
Date: 2020-01-22T22:49:32+01:00
New Revision: ed80c86c8854647ad6246544e3865e416ecfc451

URL: https://github.com/llvm/llvm-project/commit/ed80c86c8854647ad6246544e3865e416ecfc451
DIFF: https://github.com/llvm/llvm-project/commit/ed80c86c8854647ad6246544e3865e416ecfc451.diff

LOG: [PatternMatch] Add m_APInt/m_APFloat matchers accepting undef

The current m_APInt() and m_APFloat() matchers do not accept splats
that include undefs (unlike m_Zero() and other matchers for specific
values). We can't simply change the default behavior, as there are
existing transforms that would not be safe with undefs.

For this reason, I'm introducing new m_APIntAllowUndef() and
m_APFloatAllowUndef() matchers, that allow splats with undefs.
Additionally, m_APIntForbidUndef() and m_APFloatForbidUndef() are
added. These have the same behavior as the existing m_APInt() and
m_APFloat(), but serve as an explicit indication that undefs were
considered and found unsound for this transform. This helps
distinguish them from existing uses of m_APInt() where we do not
know whether undefs can or cannot be allowed without additional review.

Differential Revision: https://reviews.llvm.org/D72975

Added: 
    

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

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/IR/PatternMatch.h b/llvm/include/llvm/IR/PatternMatch.h
index bc22614c1373..214d10bd2a94 100644
--- a/llvm/include/llvm/IR/PatternMatch.h
+++ b/llvm/include/llvm/IR/PatternMatch.h
@@ -153,8 +153,10 @@ inline match_combine_and<LTy, RTy> m_CombineAnd(const LTy &L, const RTy &R) {
 
 struct apint_match {
   const APInt *&Res;
+  bool AllowUndef;
 
-  apint_match(const APInt *&R) : Res(R) {}
+  apint_match(const APInt *&Res, bool AllowUndef)
+    : Res(Res), AllowUndef(AllowUndef) {}
 
   template <typename ITy> bool match(ITy *V) {
     if (auto *CI = dyn_cast<ConstantInt>(V)) {
@@ -163,7 +165,8 @@ struct apint_match {
     }
     if (V->getType()->isVectorTy())
       if (const auto *C = dyn_cast<Constant>(V))
-        if (auto *CI = dyn_cast_or_null<ConstantInt>(C->getSplatValue())) {
+        if (auto *CI = dyn_cast_or_null<ConstantInt>(
+                C->getSplatValue(AllowUndef))) {
           Res = &CI->getValue();
           return true;
         }
@@ -175,7 +178,11 @@ struct apint_match {
 // function for both apint/apfloat.
 struct apfloat_match {
   const APFloat *&Res;
-  apfloat_match(const APFloat *&R) : Res(R) {}
+  bool AllowUndef;
+
+  apfloat_match(const APFloat *&Res, bool AllowUndef)
+      : Res(Res), AllowUndef(AllowUndef) {}
+
   template <typename ITy> bool match(ITy *V) {
     if (auto *CI = dyn_cast<ConstantFP>(V)) {
       Res = &CI->getValueAPF();
@@ -183,7 +190,8 @@ struct apfloat_match {
     }
     if (V->getType()->isVectorTy())
       if (const auto *C = dyn_cast<Constant>(V))
-        if (auto *CI = dyn_cast_or_null<ConstantFP>(C->getSplatValue())) {
+        if (auto *CI = dyn_cast_or_null<ConstantFP>(
+                C->getSplatValue(AllowUndef))) {
           Res = &CI->getValueAPF();
           return true;
         }
@@ -193,11 +201,37 @@ struct apfloat_match {
 
 /// Match a ConstantInt or splatted ConstantVector, binding the
 /// specified pointer to the contained APInt.
-inline apint_match m_APInt(const APInt *&Res) { return Res; }
+inline apint_match m_APInt(const APInt *&Res) {
+  // Forbid undefs by default to maintain previous behavior.
+  return apint_match(Res, /* AllowUndef */ false);
+}
+
+/// Match APInt while allowing undefs in splat vector constants.
+inline apint_match m_APIntAllowUndef(const APInt *&Res) {
+  return apint_match(Res, /* AllowUndef */ true);
+}
+
+/// Match APInt while forbidding undefs in splat vector constants.
+inline apint_match m_APIntForbidUndef(const APInt *&Res) {
+  return apint_match(Res, /* AllowUndef */ false);
+}
 
 /// Match a ConstantFP or splatted ConstantVector, binding the
 /// specified pointer to the contained APFloat.
-inline apfloat_match m_APFloat(const APFloat *&Res) { return Res; }
+inline apfloat_match m_APFloat(const APFloat *&Res) {
+  // Forbid undefs by default to maintain previous behavior.
+  return apfloat_match(Res, /* AllowUndef */ false);
+}
+
+/// Match APFloat while allowing undefs in splat vector constants.
+inline apfloat_match m_APFloatAllowUndef(const APFloat *&Res) {
+  return apfloat_match(Res, /* AllowUndef */ true);
+}
+
+/// Match APFloat while forbidding undefs in splat vector constants.
+inline apfloat_match m_APFloatForbidUndef(const APFloat *&Res) {
+  return apfloat_match(Res, /* AllowUndef */ false);
+}
 
 template <int64_t Val> struct constantint_match {
   template <typename ITy> bool match(ITy *V) {

diff  --git a/llvm/unittests/IR/PatternMatch.cpp b/llvm/unittests/IR/PatternMatch.cpp
index c987b7b813e7..c67e08788791 100644
--- a/llvm/unittests/IR/PatternMatch.cpp
+++ b/llvm/unittests/IR/PatternMatch.cpp
@@ -1045,6 +1045,43 @@ TEST_F(PatternMatchTest, VectorUndefInt) {
   EXPECT_TRUE(match(ScalarZero, m_Zero()));
   EXPECT_TRUE(match(VectorZero, m_Zero()));
   EXPECT_TRUE(match(VectorZeroUndef, m_Zero()));
+
+  const APInt *C;
+  // Regardless of whether undefs are allowed,
+  // a fully undef constant does not match.
+  EXPECT_FALSE(match(ScalarUndef, m_APInt(C)));
+  EXPECT_FALSE(match(ScalarUndef, m_APIntForbidUndef(C)));
+  EXPECT_FALSE(match(ScalarUndef, m_APIntAllowUndef(C)));
+  EXPECT_FALSE(match(VectorUndef, m_APInt(C)));
+  EXPECT_FALSE(match(VectorUndef, m_APIntForbidUndef(C)));
+  EXPECT_FALSE(match(VectorUndef, m_APIntAllowUndef(C)));
+
+  // We can always match simple constants and simple splats.
+  C = nullptr;
+  EXPECT_TRUE(match(ScalarZero, m_APInt(C)));
+  EXPECT_TRUE(C->isNullValue());
+  C = nullptr;
+  EXPECT_TRUE(match(ScalarZero, m_APIntForbidUndef(C)));
+  EXPECT_TRUE(C->isNullValue());
+  C = nullptr;
+  EXPECT_TRUE(match(ScalarZero, m_APIntAllowUndef(C)));
+  EXPECT_TRUE(C->isNullValue());
+  C = nullptr;
+  EXPECT_TRUE(match(VectorZero, m_APInt(C)));
+  EXPECT_TRUE(C->isNullValue());
+  C = nullptr;
+  EXPECT_TRUE(match(VectorZero, m_APIntForbidUndef(C)));
+  EXPECT_TRUE(C->isNullValue());
+  C = nullptr;
+  EXPECT_TRUE(match(VectorZero, m_APIntAllowUndef(C)));
+  EXPECT_TRUE(C->isNullValue());
+
+  // Whether splats with undef can be matched depends on the matcher.
+  EXPECT_FALSE(match(VectorZeroUndef, m_APInt(C)));
+  EXPECT_FALSE(match(VectorZeroUndef, m_APIntForbidUndef(C)));
+  C = nullptr;
+  EXPECT_TRUE(match(VectorZeroUndef, m_APIntAllowUndef(C)));
+  EXPECT_TRUE(C->isNullValue());
 }
 
 TEST_F(PatternMatchTest, VectorUndefFloat) {
@@ -1073,6 +1110,43 @@ TEST_F(PatternMatchTest, VectorUndefFloat) {
   EXPECT_TRUE(match(ScalarZero, m_AnyZeroFP()));
   EXPECT_TRUE(match(VectorZero, m_AnyZeroFP()));
   EXPECT_TRUE(match(VectorZeroUndef, m_AnyZeroFP()));
+
+  const APFloat *C;
+  // Regardless of whether undefs are allowed,
+  // a fully undef constant does not match.
+  EXPECT_FALSE(match(ScalarUndef, m_APFloat(C)));
+  EXPECT_FALSE(match(ScalarUndef, m_APFloatForbidUndef(C)));
+  EXPECT_FALSE(match(ScalarUndef, m_APFloatAllowUndef(C)));
+  EXPECT_FALSE(match(VectorUndef, m_APFloat(C)));
+  EXPECT_FALSE(match(VectorUndef, m_APFloatForbidUndef(C)));
+  EXPECT_FALSE(match(VectorUndef, m_APFloatAllowUndef(C)));
+
+  // We can always match simple constants and simple splats.
+  C = nullptr;
+  EXPECT_TRUE(match(ScalarZero, m_APFloat(C)));
+  EXPECT_TRUE(C->isZero());
+  C = nullptr;
+  EXPECT_TRUE(match(ScalarZero, m_APFloatForbidUndef(C)));
+  EXPECT_TRUE(C->isZero());
+  C = nullptr;
+  EXPECT_TRUE(match(ScalarZero, m_APFloatAllowUndef(C)));
+  EXPECT_TRUE(C->isZero());
+  C = nullptr;
+  EXPECT_TRUE(match(VectorZero, m_APFloat(C)));
+  EXPECT_TRUE(C->isZero());
+  C = nullptr;
+  EXPECT_TRUE(match(VectorZero, m_APFloatForbidUndef(C)));
+  EXPECT_TRUE(C->isZero());
+  C = nullptr;
+  EXPECT_TRUE(match(VectorZero, m_APFloatAllowUndef(C)));
+  EXPECT_TRUE(C->isZero());
+
+  // Whether splats with undef can be matched depends on the matcher.
+  EXPECT_FALSE(match(VectorZeroUndef, m_APFloat(C)));
+  EXPECT_FALSE(match(VectorZeroUndef, m_APFloatForbidUndef(C)));
+  C = nullptr;
+  EXPECT_TRUE(match(VectorZeroUndef, m_APFloatAllowUndef(C)));
+  EXPECT_TRUE(C->isZero());
 }
 
 TEST_F(PatternMatchTest, FloatingPointFNeg) {


        


More information about the llvm-commits mailing list