[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