[llvm] [PatternMatchHelpers] Factor deferred and bind matchers (NFC) (PR #191373)
Ramkumar Ramachandra via llvm-commits
llvm-commits at lists.llvm.org
Fri Apr 17 04:22:12 PDT 2026
https://github.com/artagnon updated https://github.com/llvm/llvm-project/pull/191373
>From 4087859112e33d8b6bac001bffa111ea525cf80d Mon Sep 17 00:00:00 2001
From: Ramkumar Ramachandra <artagnon at tenstorrent.com>
Date: Fri, 10 Apr 2026 10:11:25 +0100
Subject: [PATCH] [PatternMatchHelpers] Factor deferred and bind matchers (NFC)
Factor bind_ty and deferredval_ty as bind_valueptr and
match_deferred_valueptr from existing PatternMatch implementations into
PatternMatchHelpers.
---
.../Analysis/ScalarEvolutionPatternMatch.h | 52 +++-----
llvm/include/llvm/IR/PatternMatch.h | 121 ++++++------------
.../llvm/Support/PatternMatchHelpers.h | 21 +++
.../lib/Transforms/Scalar/NaryReassociate.cpp | 2 +-
.../Transforms/Vectorize/VPlanPatternMatch.h | 40 ++----
5 files changed, 89 insertions(+), 147 deletions(-)
diff --git a/llvm/include/llvm/Analysis/ScalarEvolutionPatternMatch.h b/llvm/include/llvm/Analysis/ScalarEvolutionPatternMatch.h
index 5e5208e6c7314..5aa54e1d7fb37 100644
--- a/llvm/include/llvm/Analysis/ScalarEvolutionPatternMatch.h
+++ b/llvm/include/llvm/Analysis/ScalarEvolutionPatternMatch.h
@@ -20,6 +20,19 @@
using namespace llvm::PatternMatchHelpers;
namespace llvm {
+namespace PatternMatchHelpers {
+template <typename SCEVPtrT> struct match_bind<SCEVUseT<SCEVPtrT>> {
+ SCEVUseT<SCEVPtrT> &VR;
+
+ match_bind(SCEVUseT<SCEVPtrT> &V) : VR(V) {}
+
+ template <typename ITy> bool match(ITy *V) const {
+ VR = V;
+ return true;
+ }
+};
+} // namespace PatternMatchHelpers
+
namespace SCEVPatternMatch {
template <typename Pattern> bool match(const SCEV *S, const Pattern &P) {
@@ -69,50 +82,25 @@ inline auto m_SCEV() { return m_Isa<const SCEV>(); }
inline auto m_SCEVConstant() { return m_Isa<const SCEVConstant>(); }
inline auto m_SCEVVScale() { return m_Isa<const SCEVVScale>(); }
-template <typename Class> struct bind_ty {
- Class *&VR;
-
- bind_ty(Class *&V) : VR(V) {}
-
- template <typename ITy> bool match(ITy *V) const {
- if (auto *CV = dyn_cast<Class>(V)) {
- VR = CV;
- return true;
- }
- return false;
- }
-};
-
-template <typename SCEVPtrT> struct bind_ty<SCEVUseT<SCEVPtrT>> {
- SCEVUseT<SCEVPtrT> &VR;
-
- bind_ty(SCEVUseT<SCEVPtrT> &V) : VR(V) {}
-
- template <typename ITy> bool match(ITy *V) const {
- VR = V;
- return true;
- }
-};
-
/// Match a SCEV, capturing it if we match.
-inline bind_ty<const SCEV> m_SCEV(const SCEV *&V) { return V; }
+inline match_bind<const SCEV> m_SCEV(const SCEV *&V) { return V; }
template <typename SCEVPtrT>
-inline bind_ty<SCEVUseT<SCEVPtrT>> m_SCEV(SCEVUseT<SCEVPtrT> &V) {
+inline match_bind<SCEVUseT<SCEVPtrT>> m_SCEV(SCEVUseT<SCEVPtrT> &V) {
return V;
}
-inline bind_ty<const SCEVConstant> m_SCEVConstant(const SCEVConstant *&V) {
+inline match_bind<const SCEVConstant> m_SCEVConstant(const SCEVConstant *&V) {
return V;
}
-inline bind_ty<const SCEVUnknown> m_SCEVUnknown(const SCEVUnknown *&V) {
+inline match_bind<const SCEVUnknown> m_SCEVUnknown(const SCEVUnknown *&V) {
return V;
}
-inline bind_ty<const SCEVAddExpr> m_scev_Add(const SCEVAddExpr *&V) {
+inline match_bind<const SCEVAddExpr> m_scev_Add(const SCEVAddExpr *&V) {
return V;
}
-inline bind_ty<const SCEVMulExpr> m_scev_Mul(const SCEVMulExpr *&V) {
+inline match_bind<const SCEVMulExpr> m_scev_Mul(const SCEVMulExpr *&V) {
return V;
}
@@ -390,7 +378,7 @@ struct specificloop_ty {
inline specificloop_ty m_SpecificLoop(const Loop *L) { return L; }
-inline bind_ty<const Loop> m_Loop(const Loop *&L) { return L; }
+inline match_bind<const Loop> m_Loop(const Loop *&L) { return L; }
template <typename Op0_t, typename Op1_t>
inline SCEVAffineAddRec_match<Op0_t, Op1_t, match_isa<const Loop>>
diff --git a/llvm/include/llvm/IR/PatternMatch.h b/llvm/include/llvm/IR/PatternMatch.h
index 8399c252f1c2d..26a8231fd46f8 100644
--- a/llvm/include/llvm/IR/PatternMatch.h
+++ b/llvm/include/llvm/IR/PatternMatch.h
@@ -803,116 +803,79 @@ inline cstfp_pred_ty<is_non_zero_not_denormal_fp> m_NonZeroNotDenormalFP() {
///////////////////////////////////////////////////////////////////////////////
-template <typename Class> struct bind_ty {
- Class *&VR;
-
- bind_ty(Class *&V) : VR(V) {}
-
- template <typename ITy> bool match(ITy *V) const {
- if (auto *CV = dyn_cast<Class>(V)) {
- VR = CV;
- return true;
- }
- return false;
- }
-};
-
-/// Check whether the value has the given Class and matches the nested
-/// pattern. Capture it into the provided variable if successful.
-template <typename Class, typename MatchTy> struct bind_and_match_ty {
- Class *&VR;
- MatchTy Match;
-
- bind_and_match_ty(Class *&V, const MatchTy &Match) : VR(V), Match(Match) {}
-
- template <typename ITy> bool match(ITy *V) const {
- auto *CV = dyn_cast<Class>(V);
- if (CV && Match.match(V)) {
- VR = CV;
- return true;
- }
- return false;
- }
-};
-
/// Match a value, capturing it if we match.
-inline bind_ty<Value> m_Value(Value *&V) { return V; }
-inline bind_ty<const Value> m_Value(const Value *&V) { return V; }
+inline match_bind<Value> m_Value(Value *&V) { return V; }
+inline match_bind<const Value> m_Value(const Value *&V) { return V; }
/// Match against the nested pattern, and capture the value if we match.
-template <typename MatchTy>
-inline bind_and_match_ty<Value, MatchTy> m_Value(Value *&V,
- const MatchTy &Match) {
- return {V, Match};
+template <typename Pattern> inline auto m_Value(Value *&V, const Pattern &P) {
+ return m_CombineAnd(P, match_bind<Value>(V));
}
/// Match against the nested pattern, and capture the value if we match.
-template <typename MatchTy>
-inline bind_and_match_ty<const Value, MatchTy> m_Value(const Value *&V,
- const MatchTy &Match) {
- return {V, Match};
+template <typename Pattern>
+inline auto m_Value(const Value *&V, const Pattern &P) {
+ return m_CombineAnd(P, match_bind<const Value>(V));
}
/// Match an instruction, capturing it if we match.
-inline bind_ty<Instruction> m_Instruction(Instruction *&I) { return I; }
-inline bind_ty<const Instruction> m_Instruction(const Instruction *&I) {
+inline match_bind<Instruction> m_Instruction(Instruction *&I) { return I; }
+inline match_bind<const Instruction> m_Instruction(const Instruction *&I) {
return I;
}
/// Match against the nested pattern, and capture the instruction if we match.
-template <typename MatchTy>
-inline bind_and_match_ty<Instruction, MatchTy>
-m_Instruction(Instruction *&I, const MatchTy &Match) {
- return {I, Match};
+template <typename Pattern>
+inline auto m_Instruction(Instruction *&I, const Pattern &P) {
+ return m_CombineAnd(P, match_bind<Instruction>(I));
}
-template <typename MatchTy>
-inline bind_and_match_ty<const Instruction, MatchTy>
-m_Instruction(const Instruction *&I, const MatchTy &Match) {
- return {I, Match};
+template <typename Pattern>
+inline auto m_Instruction(const Instruction *&I, const Pattern &P) {
+ return m_CombineAnd(P, match_bind<const Instruction>(I));
}
/// Match a unary operator, capturing it if we match.
-inline bind_ty<UnaryOperator> m_UnOp(UnaryOperator *&I) { return I; }
-inline bind_ty<const UnaryOperator> m_UnOp(const UnaryOperator *&I) {
+inline match_bind<UnaryOperator> m_UnOp(UnaryOperator *&I) { return I; }
+inline match_bind<const UnaryOperator> m_UnOp(const UnaryOperator *&I) {
return I;
}
/// Match a binary operator, capturing it if we match.
-inline bind_ty<BinaryOperator> m_BinOp(BinaryOperator *&I) { return I; }
-inline bind_ty<const BinaryOperator> m_BinOp(const BinaryOperator *&I) {
+inline match_bind<BinaryOperator> m_BinOp(BinaryOperator *&I) { return I; }
+inline match_bind<const BinaryOperator> m_BinOp(const BinaryOperator *&I) {
return I;
}
/// Match any intrinsic call, capturing it if we match.
-inline bind_ty<IntrinsicInst> m_AnyIntrinsic(IntrinsicInst *&I) { return I; }
-inline bind_ty<const IntrinsicInst> m_AnyIntrinsic(const IntrinsicInst *&I) {
+inline match_bind<IntrinsicInst> m_AnyIntrinsic(IntrinsicInst *&I) { return I; }
+inline match_bind<const IntrinsicInst> m_AnyIntrinsic(const IntrinsicInst *&I) {
return I;
}
/// Match a with overflow intrinsic, capturing it if we match.
-inline bind_ty<WithOverflowInst> m_WithOverflowInst(WithOverflowInst *&I) {
+inline match_bind<WithOverflowInst> m_WithOverflowInst(WithOverflowInst *&I) {
return I;
}
-inline bind_ty<const WithOverflowInst>
+inline match_bind<const WithOverflowInst>
m_WithOverflowInst(const WithOverflowInst *&I) {
return I;
}
/// Match an UndefValue, capturing the value if we match.
-inline bind_ty<UndefValue> m_UndefValue(UndefValue *&U) { return U; }
+inline match_bind<UndefValue> m_UndefValue(UndefValue *&U) { return U; }
/// Match a Constant, capturing the value if we match.
-inline bind_ty<Constant> m_Constant(Constant *&C) { return C; }
+inline match_bind<Constant> m_Constant(Constant *&C) { return C; }
/// Match a ConstantInt, capturing the value if we match.
-inline bind_ty<ConstantInt> m_ConstantInt(ConstantInt *&CI) { return CI; }
+inline match_bind<ConstantInt> m_ConstantInt(ConstantInt *&CI) { return CI; }
/// Match a ConstantFP, capturing the value if we match.
-inline bind_ty<ConstantFP> m_ConstantFP(ConstantFP *&C) { return C; }
+inline match_bind<ConstantFP> m_ConstantFP(ConstantFP *&C) { return C; }
/// Match a ConstantExpr, capturing the value if we match.
-inline bind_ty<ConstantExpr> m_ConstantExpr(ConstantExpr *&C) { return C; }
+inline match_bind<ConstantExpr> m_ConstantExpr(ConstantExpr *&C) { return C; }
/// Match a basic block value, capturing it if we match.
-inline bind_ty<BasicBlock> m_BasicBlock(BasicBlock *&V) { return V; }
-inline bind_ty<const BasicBlock> m_BasicBlock(const BasicBlock *&V) {
+inline match_bind<BasicBlock> m_BasicBlock(BasicBlock *&V) { return V; }
+inline match_bind<const BasicBlock> m_BasicBlock(const BasicBlock *&V) {
return V;
}
@@ -963,7 +926,7 @@ inline bind_immconstant_ty m_ImmConstant(Constant *&C) {
return bind_immconstant_ty(C);
}
-/// Match a specified Value*.
+/// Matcher for specified Value*.
struct specificval_ty {
const Value *Val;
@@ -975,24 +938,14 @@ struct specificval_ty {
/// Match if we have a specific specified value.
inline specificval_ty m_Specific(const Value *V) { return V; }
-/// Stores a reference to the Value *, not the Value * itself,
-/// thus can be used in commutative matchers.
-template <typename Class> struct deferredval_ty {
- Class *const &Val;
-
- deferredval_ty(Class *const &V) : Val(V) {}
-
- template <typename ITy> bool match(ITy *const V) const { return V == Val; }
-};
-
/// Like m_Specific(), but works if the specific value to match is determined
/// as part of the same match() expression. For example:
/// m_Add(m_Value(X), m_Specific(X)) is incorrect, because m_Specific() will
/// bind X before the pattern match starts.
/// m_Add(m_Value(X), m_Deferred(X)) is correct, and will check against
/// whichever value m_Value(X) populated.
-inline deferredval_ty<Value> m_Deferred(Value *const &V) { return V; }
-inline deferredval_ty<const Value> m_Deferred(const Value *const &V) {
+inline match_deferred<Value> m_Deferred(Value *const &V) { return V; }
+inline match_deferred<const Value> m_Deferred(const Value *const &V) {
return V;
}
@@ -1110,10 +1063,10 @@ inline specific_bbval m_SpecificBB(BasicBlock *BB) {
}
/// A commutative-friendly version of m_Specific().
-inline deferredval_ty<BasicBlock> m_Deferred(BasicBlock *const &BB) {
+inline match_deferred<BasicBlock> m_Deferred(BasicBlock *const &BB) {
return BB;
}
-inline deferredval_ty<const BasicBlock>
+inline match_deferred<const BasicBlock>
m_Deferred(const BasicBlock *const &BB) {
return BB;
}
@@ -2444,9 +2397,9 @@ struct brc_match {
};
template <typename Cond_t>
-inline brc_match<Cond_t, bind_ty<BasicBlock>, bind_ty<BasicBlock>>
+inline brc_match<Cond_t, match_bind<BasicBlock>, match_bind<BasicBlock>>
m_Br(const Cond_t &C, BasicBlock *&T, BasicBlock *&F) {
- return brc_match<Cond_t, bind_ty<BasicBlock>, bind_ty<BasicBlock>>(
+ return brc_match<Cond_t, match_bind<BasicBlock>, match_bind<BasicBlock>>(
C, m_BasicBlock(T), m_BasicBlock(F));
}
diff --git a/llvm/include/llvm/Support/PatternMatchHelpers.h b/llvm/include/llvm/Support/PatternMatchHelpers.h
index 5bfa99d9ce93b..4549a14b740cd 100644
--- a/llvm/include/llvm/Support/PatternMatchHelpers.h
+++ b/llvm/include/llvm/Support/PatternMatchHelpers.h
@@ -79,6 +79,27 @@ template <typename... To, typename SubPattern>
inline auto m_Isa(const SubPattern &P) { // NOLINT
return m_CombineAnd(m_Isa<To...>(), P);
}
+
+/// Matcher for a specific value, but stores a reference to the value, not the
+/// value itself.
+template <typename Ty> struct match_deferred { // NOLINT
+ Ty *const &Val;
+ match_deferred(Ty *const &V) : Val(V) {}
+ template <typename ITy> bool match(ITy *const V) const { return V == Val; }
+};
+
+/// Matcher to bind the captured value.
+template <typename Ty> struct match_bind { // NOLINT
+ Ty *&VR;
+ match_bind(Ty *&V) : VR(V) {}
+ template <typename ITy> bool match(ITy *V) const {
+ if (auto *CV = dyn_cast<Ty>(V)) {
+ VR = CV;
+ return true;
+ }
+ return false;
+ }
+};
} // namespace llvm::PatternMatchHelpers
#endif // LLVM_SUPPORT_PATTERNMATCHHELPERS_H
diff --git a/llvm/lib/Transforms/Scalar/NaryReassociate.cpp b/llvm/lib/Transforms/Scalar/NaryReassociate.cpp
index b0a33710c25bc..9603671ed50ca 100644
--- a/llvm/lib/Transforms/Scalar/NaryReassociate.cpp
+++ b/llvm/lib/Transforms/Scalar/NaryReassociate.cpp
@@ -278,7 +278,7 @@ NaryReassociatePass::matchAndReassociateMinOrMax(Instruction *I,
Value *RHS = nullptr;
auto MinMaxMatcher =
- MaxMin_match<ICmpInst, bind_ty<Value>, bind_ty<Value>, PredT>(
+ MaxMin_match<ICmpInst, match_bind<Value>, match_bind<Value>, PredT>(
m_Value(LHS), m_Value(RHS));
if (match(I, MinMaxMatcher)) {
OrigSCEV = SE->getSCEV(I);
diff --git a/llvm/lib/Transforms/Vectorize/VPlanPatternMatch.h b/llvm/lib/Transforms/Vectorize/VPlanPatternMatch.h
index 6ce0c8b80571d..6e1a2676ba9a9 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanPatternMatch.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanPatternMatch.h
@@ -49,20 +49,6 @@ template <typename Pattern> bool match(VPSingleDefRecipe *R, const Pattern &P) {
/// Match an arbitrary VPValue and ignore it.
inline auto m_VPValue() { return m_Isa<VPValue>(); }
-template <typename Class> struct bind_ty {
- Class *&VR;
-
- bind_ty(Class *&V) : VR(V) {}
-
- template <typename ITy> bool match(ITy *V) const {
- if (auto *CV = dyn_cast<Class>(V)) {
- VR = CV;
- return true;
- }
- return false;
- }
-};
-
/// Match a specified VPValue.
struct specificval_ty {
const VPValue *Val;
@@ -74,23 +60,13 @@ struct specificval_ty {
inline specificval_ty m_Specific(const VPValue *VPV) { return VPV; }
-/// Stores a reference to the VPValue *, not the VPValue * itself,
-/// thus can be used in commutative matchers.
-struct deferredval_ty {
- VPValue *const &Val;
-
- deferredval_ty(VPValue *const &V) : Val(V) {}
-
- bool match(const VPValue *const V) const { return V == Val; }
-};
-
/// Like m_Specific(), but works if the specific value to match is determined
/// as part of the same match() expression. For example:
/// m_Mul(m_VPValue(X), m_Specific(X)) is incorrect, because m_Specific() will
/// bind X before the pattern match starts.
/// m_Mul(m_VPValue(X), m_Deferred(X)) is correct, and will check against
/// whichever value m_VPValue(X) populated.
-inline deferredval_ty m_Deferred(VPValue *const &V) { return V; }
+inline match_deferred<VPValue> m_Deferred(VPValue *const &V) { return V; }
/// Match an integer constant if Pred::isValue returns true for the APInt. \p
/// BitWidth optionally specifies the bitwidth the matched constant must have.
@@ -224,18 +200,21 @@ inline match_poison m_Poison() { return match_poison(); }
inline bind_const_int m_ConstantInt(uint64_t &C) { return C; }
/// Match a VPValue, capturing it if we match.
-inline bind_ty<VPValue> m_VPValue(VPValue *&V) { return V; }
+inline match_bind<VPValue> m_VPValue(VPValue *&V) { return V; }
/// Match a VPIRValue.
-inline bind_ty<VPIRValue> m_VPIRValue(VPIRValue *&V) { return V; }
+inline match_bind<VPIRValue> m_VPIRValue(VPIRValue *&V) { return V; }
/// Match a VPSingleDefRecipe, capturing if we match.
-inline bind_ty<VPSingleDefRecipe> m_VPSingleDefRecipe(VPSingleDefRecipe *&V) {
+inline match_bind<VPSingleDefRecipe>
+m_VPSingleDefRecipe(VPSingleDefRecipe *&V) {
return V;
}
/// Match a VPInstruction, capturing if we match.
-inline bind_ty<VPInstruction> m_VPInstruction(VPInstruction *&V) { return V; }
+inline match_bind<VPInstruction> m_VPInstruction(VPInstruction *&V) {
+ return V;
+}
template <typename Ops_t, unsigned Opcode, bool Commutative,
typename... RecipeTys>
@@ -1071,7 +1050,8 @@ template <typename T> inline OneUse_match<T> m_OneUse(const T &SubPattern) {
return SubPattern;
}
-inline bind_ty<VPReductionPHIRecipe> m_ReductionPhi(VPReductionPHIRecipe *&V) {
+inline match_bind<VPReductionPHIRecipe>
+m_ReductionPhi(VPReductionPHIRecipe *&V) {
return V;
}
More information about the llvm-commits
mailing list