[llvm] [Support][Casting] Add predicates for `isa*` functions (PR #83753)

Jakub Kuderski via llvm-commits llvm-commits at lists.llvm.org
Tue Mar 5 17:46:52 PST 2024


https://github.com/kuhar updated https://github.com/llvm/llvm-project/pull/83753

>From b798fd576f4722421f77bb2277207c6aba88ef72 Mon Sep 17 00:00:00 2001
From: Jakub Kuderski <jakub at nod-labs.com>
Date: Sun, 3 Mar 2024 20:57:29 -0500
Subject: [PATCH 1/3] [Support][Casting] Add predicates for `isa*` functions

Expose function objects that call into `llvm::isa` and
`llvm::isa_and_present`, such that these type checks can be used as
predicates in generic algorithms.

Before this change, `llvm::isa*` functions cannot be easily used without
knowing both the argument type and the checked types, which leads to
them being wrapped in lambdas. For example:
```c++
llvm::all_of(myTypes,
             [](auto type) { return llvm::isa<VectorType>(type); });
```

With this PR the example above becomes:
```c++
llvm::all_of(myTypes, llvm::IsaPred<VectorType>);
```

As an alternative solution, I considered redefining `isa*` as function
objects, but I decided against doing that because it would create
assymetry with other cast *functions* and could break code that depends
on them being actual functions.
---
 llvm/include/llvm/Support/Casting.h | 46 +++++++++++++++++++++++++++++
 llvm/unittests/Support/Casting.cpp  | 14 +++++++++
 2 files changed, 60 insertions(+)

diff --git a/llvm/include/llvm/Support/Casting.h b/llvm/include/llvm/Support/Casting.h
index 2391c1a531a5be..4c0ae59b1aa986 100644
--- a/llvm/include/llvm/Support/Casting.h
+++ b/llvm/include/llvm/Support/Casting.h
@@ -801,6 +801,52 @@ template <class X, class Y>
   return unique_dyn_cast_or_null<X, Y>(Val);
 }
 
+//===----------------------------------------------------------------------===//
+// Isa Predicates
+//===----------------------------------------------------------------------===//
+
+/// These are wrappers over isa* function that allow them to be used in generic
+/// algorithms such as `llvm:all_of`, `llvm::none_of`, etc. This is accomplished
+/// by exposing the isa* functions through function objects with a generic
+/// function call operator.
+
+namespace detail {
+template <typename... Types> struct IsaCheckPredicate {
+  template <typename T> bool operator()(const T &Val) const {
+    return isa<Types...>(Val);
+  }
+};
+
+template <typename... Types> struct IsaAndPresentCheckPredicate {
+  template <typename T> bool operator()(const T &Val) const {
+    return isa_and_present<Types...>(Val);
+  }
+};
+} // namespace detail
+
+/// Function object wrapper for the `llvm::isa` type check. The function call
+/// operator returns true when the value can be cast to any type in `Types`.
+/// Example:
+/// ```
+/// SmallVector<Type> myTypes = ...;
+/// if (llvm::all_of(myTypes, llvm::IsaPred<VectorType>))
+///   ...
+/// ```
+template <typename... Types>
+inline constexpr detail::IsaCheckPredicate<Types...> IsaPred{};
+
+/// Function object wrapper for the `llvm::isa_and_present` type check. The
+/// function call operator returns true when the value can be cast to any type
+/// in `Types`, or if the value is not present (e.g., nullptr). Example:
+/// ```
+/// SmallVector<Type> myTypes = ...;
+/// if (llvm::all_of(myTypes, llvm::IsaAndPresnetPred<VectorType>))
+///   ...
+/// ```
+template <typename... Types>
+inline constexpr detail::IsaAndPresentCheckPredicate<Types...>
+    IsaAndPresentPred{};
+
 } // end namespace llvm
 
 #endif // LLVM_SUPPORT_CASTING_H
diff --git a/llvm/unittests/Support/Casting.cpp b/llvm/unittests/Support/Casting.cpp
index a9256548145986..2f8b0c50e1955c 100644
--- a/llvm/unittests/Support/Casting.cpp
+++ b/llvm/unittests/Support/Casting.cpp
@@ -282,6 +282,20 @@ TEST(CastingTest, dyn_cast_if_present) {
   EXPECT_FALSE(t4.hasValue);
 }
 
+TEST(CastingTest, isa_check_predicates) {
+  auto IsaFoo = IsaPred<foo>;
+  auto IsaAndPresentFoo = IsaAndPresentPred<foo>;
+  EXPECT_TRUE(IsaFoo(B1));
+  EXPECT_TRUE(IsaFoo(B2));
+  EXPECT_TRUE(IsaFoo(B3));
+  EXPECT_TRUE(IsaPred<foo>(B4));
+  EXPECT_TRUE((IsaPred<foo, bar>(B4)));
+  EXPECT_TRUE(IsaAndPresentFoo(B2));
+  EXPECT_TRUE(IsaAndPresentFoo(B4));
+  EXPECT_FALSE(IsaAndPresentPred<foo>(fub()));
+  EXPECT_FALSE((IsaAndPresentPred<foo, bar>(fub())));
+}
+
 std::unique_ptr<derived> newd() { return std::make_unique<derived>(); }
 std::unique_ptr<base> newb() { return std::make_unique<derived>(); }
 

>From 9b80de83f0cfea9cefbdf5bfab728b6dd65d0adb Mon Sep 17 00:00:00 2001
From: Jakub Kuderski <jakub at nod-labs.com>
Date: Sun, 3 Mar 2024 21:10:43 -0500
Subject: [PATCH 2/3] Fix typos

---
 llvm/include/llvm/Support/Casting.h | 2 +-
 llvm/unittests/Support/Casting.cpp  | 3 ++-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/llvm/include/llvm/Support/Casting.h b/llvm/include/llvm/Support/Casting.h
index 4c0ae59b1aa986..895d9241b04024 100644
--- a/llvm/include/llvm/Support/Casting.h
+++ b/llvm/include/llvm/Support/Casting.h
@@ -840,7 +840,7 @@ inline constexpr detail::IsaCheckPredicate<Types...> IsaPred{};
 /// in `Types`, or if the value is not present (e.g., nullptr). Example:
 /// ```
 /// SmallVector<Type> myTypes = ...;
-/// if (llvm::all_of(myTypes, llvm::IsaAndPresnetPred<VectorType>))
+/// if (llvm::all_of(myTypes, llvm::IsaAndPresentPred<VectorType>))
 ///   ...
 /// ```
 template <typename... Types>
diff --git a/llvm/unittests/Support/Casting.cpp b/llvm/unittests/Support/Casting.cpp
index 2f8b0c50e1955c..a128cedaf3988d 100644
--- a/llvm/unittests/Support/Casting.cpp
+++ b/llvm/unittests/Support/Casting.cpp
@@ -284,12 +284,13 @@ TEST(CastingTest, dyn_cast_if_present) {
 
 TEST(CastingTest, isa_check_predicates) {
   auto IsaFoo = IsaPred<foo>;
-  auto IsaAndPresentFoo = IsaAndPresentPred<foo>;
   EXPECT_TRUE(IsaFoo(B1));
   EXPECT_TRUE(IsaFoo(B2));
   EXPECT_TRUE(IsaFoo(B3));
   EXPECT_TRUE(IsaPred<foo>(B4));
   EXPECT_TRUE((IsaPred<foo, bar>(B4)));
+
+  auto IsaAndPresentFoo = IsaAndPresentPred<foo>;
   EXPECT_TRUE(IsaAndPresentFoo(B2));
   EXPECT_TRUE(IsaAndPresentFoo(B4));
   EXPECT_FALSE(IsaAndPresentPred<foo>(fub()));

>From 287da8e6e2c5f7c0baed9ee188e0c6228fa94b84 Mon Sep 17 00:00:00 2001
From: Jakub Kuderski <jakub at nod-labs.com>
Date: Tue, 5 Mar 2024 20:45:14 -0500
Subject: [PATCH 3/3] Add missing [[nodiscard]] attributes

---
 llvm/include/llvm/Support/Casting.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/include/llvm/Support/Casting.h b/llvm/include/llvm/Support/Casting.h
index 895d9241b04024..14a32ccd0e0dc9 100644
--- a/llvm/include/llvm/Support/Casting.h
+++ b/llvm/include/llvm/Support/Casting.h
@@ -812,13 +812,13 @@ template <class X, class Y>
 
 namespace detail {
 template <typename... Types> struct IsaCheckPredicate {
-  template <typename T> bool operator()(const T &Val) const {
+  template <typename T> [[nodiscard]] bool operator()(const T &Val) const {
     return isa<Types...>(Val);
   }
 };
 
 template <typename... Types> struct IsaAndPresentCheckPredicate {
-  template <typename T> bool operator()(const T &Val) const {
+  template <typename T> [[nodiscard]] bool operator()(const T &Val) const {
     return isa_and_present<Types...>(Val);
   }
 };



More information about the llvm-commits mailing list