[llvm] [Support][Casting] Add predicates for `isa*` functions (PR #83753)
Jakub Kuderski via llvm-commits
llvm-commits at lists.llvm.org
Sun Mar 3 18:08:22 PST 2024
https://github.com/kuhar created https://github.com/llvm/llvm-project/pull/83753
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 asymmetry with other cast *functions* and could break code that depends on them being actual functions.
>From 0ebb22b6030a0a2525a5d0a0b569b7244d1c966e 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] [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>(); }
More information about the llvm-commits
mailing list