[llvm] [Support][Casting] Add predicates for `isa*` functions (PR #83753)
Fangrui Song via llvm-commits
llvm-commits at lists.llvm.org
Sun Mar 3 18:10:55 PST 2024
https://github.com/MaskRay updated https://github.com/llvm/llvm-project/pull/83753
>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 1/2] [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 d74118d77c7d8e6df1be2f5915c487e47be469c1 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/2] 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()));
More information about the llvm-commits
mailing list