xref: /llvm-project/llvm/lib/Transforms/Vectorize/VPlanPatternMatch.h (revision df4a615c988f3ae56f7e68a7df86acb60f16493a)
12435dcd8SFlorian Hahn //===- VPlanPatternMatch.h - Match on VPValues and recipes ------*- C++ -*-===//
22435dcd8SFlorian Hahn //
32435dcd8SFlorian Hahn // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42435dcd8SFlorian Hahn // See https://llvm.org/LICENSE.txt for license information.
52435dcd8SFlorian Hahn // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
62435dcd8SFlorian Hahn //
72435dcd8SFlorian Hahn //===----------------------------------------------------------------------===//
82435dcd8SFlorian Hahn //
92435dcd8SFlorian Hahn // This file provides a simple and efficient mechanism for performing general
102435dcd8SFlorian Hahn // tree-based pattern matches on the VPlan values and recipes, based on
112435dcd8SFlorian Hahn // LLVM's IR pattern matchers.
122435dcd8SFlorian Hahn //
132435dcd8SFlorian Hahn // Currently it provides generic matchers for unary and binary VPInstructions,
142435dcd8SFlorian Hahn // and specialized matchers like m_Not, m_ActiveLaneMask, m_BranchOnCond,
152435dcd8SFlorian Hahn // m_BranchOnCount to match specific VPInstructions.
162435dcd8SFlorian Hahn // TODO: Add missing matchers for additional opcodes and recipes as needed.
172435dcd8SFlorian Hahn //
182435dcd8SFlorian Hahn //===----------------------------------------------------------------------===//
192435dcd8SFlorian Hahn 
202435dcd8SFlorian Hahn #ifndef LLVM_TRANSFORM_VECTORIZE_VPLANPATTERNMATCH_H
212435dcd8SFlorian Hahn #define LLVM_TRANSFORM_VECTORIZE_VPLANPATTERNMATCH_H
222435dcd8SFlorian Hahn 
232435dcd8SFlorian Hahn #include "VPlan.h"
242435dcd8SFlorian Hahn 
252435dcd8SFlorian Hahn namespace llvm {
262435dcd8SFlorian Hahn namespace VPlanPatternMatch {
272435dcd8SFlorian Hahn 
282435dcd8SFlorian Hahn template <typename Val, typename Pattern> bool match(Val *V, const Pattern &P) {
2928047750SRamkumar Ramachandra   return P.match(V);
302435dcd8SFlorian Hahn }
312435dcd8SFlorian Hahn 
3299741ac2SFlorian Hahn template <typename Pattern> bool match(VPUser *U, const Pattern &P) {
3399741ac2SFlorian Hahn   auto *R = dyn_cast<VPRecipeBase>(U);
3499741ac2SFlorian Hahn   return R && match(R, P);
3599741ac2SFlorian Hahn }
3699741ac2SFlorian Hahn 
372435dcd8SFlorian Hahn template <typename Class> struct class_match {
3828047750SRamkumar Ramachandra   template <typename ITy> bool match(ITy *V) const { return isa<Class>(V); }
392435dcd8SFlorian Hahn };
402435dcd8SFlorian Hahn 
412435dcd8SFlorian Hahn /// Match an arbitrary VPValue and ignore it.
422435dcd8SFlorian Hahn inline class_match<VPValue> m_VPValue() { return class_match<VPValue>(); }
432435dcd8SFlorian Hahn 
442435dcd8SFlorian Hahn template <typename Class> struct bind_ty {
452435dcd8SFlorian Hahn   Class *&VR;
462435dcd8SFlorian Hahn 
472435dcd8SFlorian Hahn   bind_ty(Class *&V) : VR(V) {}
482435dcd8SFlorian Hahn 
4928047750SRamkumar Ramachandra   template <typename ITy> bool match(ITy *V) const {
502435dcd8SFlorian Hahn     if (auto *CV = dyn_cast<Class>(V)) {
512435dcd8SFlorian Hahn       VR = CV;
522435dcd8SFlorian Hahn       return true;
532435dcd8SFlorian Hahn     }
542435dcd8SFlorian Hahn     return false;
552435dcd8SFlorian Hahn   }
562435dcd8SFlorian Hahn };
572435dcd8SFlorian Hahn 
584480a22cSMel Chen /// Match a specified VPValue.
594480a22cSMel Chen struct specificval_ty {
604480a22cSMel Chen   const VPValue *Val;
614480a22cSMel Chen 
624480a22cSMel Chen   specificval_ty(const VPValue *V) : Val(V) {}
634480a22cSMel Chen 
644480a22cSMel Chen   bool match(VPValue *VPV) const { return VPV == Val; }
654480a22cSMel Chen };
664480a22cSMel Chen 
674480a22cSMel Chen inline specificval_ty m_Specific(const VPValue *VPV) { return VPV; }
684480a22cSMel Chen 
69fd93a5e3SFlorian Hahn /// Match a specified integer value or vector of all elements of that
70dadf6f2cSFlorian Hahn /// value. \p BitWidth optionally specifies the bitwidth the matched constant
71dadf6f2cSFlorian Hahn /// must have. If it is 0, the matched constant can have any bitwidth.
72dadf6f2cSFlorian Hahn template <unsigned BitWidth = 0> struct specific_intval {
73fd93a5e3SFlorian Hahn   APInt Val;
74fd93a5e3SFlorian Hahn 
75fd93a5e3SFlorian Hahn   specific_intval(APInt V) : Val(std::move(V)) {}
76fd93a5e3SFlorian Hahn 
7728047750SRamkumar Ramachandra   bool match(VPValue *VPV) const {
78fd93a5e3SFlorian Hahn     if (!VPV->isLiveIn())
79fd93a5e3SFlorian Hahn       return false;
80fd93a5e3SFlorian Hahn     Value *V = VPV->getLiveInIRValue();
81e1833e3aSFlorian Hahn     if (!V)
82e1833e3aSFlorian Hahn       return false;
83fd93a5e3SFlorian Hahn     const auto *CI = dyn_cast<ConstantInt>(V);
84fd93a5e3SFlorian Hahn     if (!CI && V->getType()->isVectorTy())
85fd93a5e3SFlorian Hahn       if (const auto *C = dyn_cast<Constant>(V))
86fd93a5e3SFlorian Hahn         CI = dyn_cast_or_null<ConstantInt>(
871baa3850SNikita Popov             C->getSplatValue(/*AllowPoison=*/false));
88dadf6f2cSFlorian Hahn     if (!CI)
89dadf6f2cSFlorian Hahn       return false;
90fd93a5e3SFlorian Hahn 
911d9b3222SFlorian Hahn     if (BitWidth != 0 && CI->getBitWidth() != BitWidth)
921d9b3222SFlorian Hahn       return false;
93dadf6f2cSFlorian Hahn     return APInt::isSameValue(CI->getValue(), Val);
94fd93a5e3SFlorian Hahn   }
95fd93a5e3SFlorian Hahn };
96fd93a5e3SFlorian Hahn 
97dadf6f2cSFlorian Hahn inline specific_intval<0> m_SpecificInt(uint64_t V) {
98dadf6f2cSFlorian Hahn   return specific_intval<0>(APInt(64, V));
99fd93a5e3SFlorian Hahn }
100fd93a5e3SFlorian Hahn 
101dadf6f2cSFlorian Hahn inline specific_intval<1> m_False() { return specific_intval<1>(APInt(64, 0)); }
102dadf6f2cSFlorian Hahn 
1031d9b3222SFlorian Hahn inline specific_intval<1> m_True() { return specific_intval<1>(APInt(64, 1)); }
1041d9b3222SFlorian Hahn 
105fd93a5e3SFlorian Hahn /// Matching combinators
106fd93a5e3SFlorian Hahn template <typename LTy, typename RTy> struct match_combine_or {
107fd93a5e3SFlorian Hahn   LTy L;
108fd93a5e3SFlorian Hahn   RTy R;
109fd93a5e3SFlorian Hahn 
110fd93a5e3SFlorian Hahn   match_combine_or(const LTy &Left, const RTy &Right) : L(Left), R(Right) {}
111fd93a5e3SFlorian Hahn 
11228047750SRamkumar Ramachandra   template <typename ITy> bool match(ITy *V) const {
113fd93a5e3SFlorian Hahn     if (L.match(V))
114fd93a5e3SFlorian Hahn       return true;
115fd93a5e3SFlorian Hahn     if (R.match(V))
116fd93a5e3SFlorian Hahn       return true;
117fd93a5e3SFlorian Hahn     return false;
118fd93a5e3SFlorian Hahn   }
119fd93a5e3SFlorian Hahn };
120fd93a5e3SFlorian Hahn 
121fd93a5e3SFlorian Hahn template <typename LTy, typename RTy>
122fd93a5e3SFlorian Hahn inline match_combine_or<LTy, RTy> m_CombineOr(const LTy &L, const RTy &R) {
123fd93a5e3SFlorian Hahn   return match_combine_or<LTy, RTy>(L, R);
124fd93a5e3SFlorian Hahn }
125fd93a5e3SFlorian Hahn 
1262435dcd8SFlorian Hahn /// Match a VPValue, capturing it if we match.
1272435dcd8SFlorian Hahn inline bind_ty<VPValue> m_VPValue(VPValue *&V) { return V; }
1282435dcd8SFlorian Hahn 
129fd93a5e3SFlorian Hahn namespace detail {
130fd93a5e3SFlorian Hahn 
131fd93a5e3SFlorian Hahn /// A helper to match an opcode against multiple recipe types.
132fd93a5e3SFlorian Hahn template <unsigned Opcode, typename...> struct MatchRecipeAndOpcode {};
133fd93a5e3SFlorian Hahn 
134fd93a5e3SFlorian Hahn template <unsigned Opcode, typename RecipeTy>
135fd93a5e3SFlorian Hahn struct MatchRecipeAndOpcode<Opcode, RecipeTy> {
136fd93a5e3SFlorian Hahn   static bool match(const VPRecipeBase *R) {
137fd93a5e3SFlorian Hahn     auto *DefR = dyn_cast<RecipeTy>(R);
138dac0f7e8SFlorian Hahn     // Check for recipes that do not have opcodes.
139dac0f7e8SFlorian Hahn     if constexpr (std::is_same<RecipeTy, VPScalarIVStepsRecipe>::value ||
1401d9b3222SFlorian Hahn                   std::is_same<RecipeTy, VPCanonicalIVPHIRecipe>::value ||
141e1833e3aSFlorian Hahn                   std::is_same<RecipeTy, VPWidenSelectRecipe>::value ||
142*df4a615cSFlorian Hahn                   std::is_same<RecipeTy, VPDerivedIVRecipe>::value ||
143*df4a615cSFlorian Hahn                   std::is_same<RecipeTy, VPWidenGEPRecipe>::value)
144dac0f7e8SFlorian Hahn       return DefR;
145dac0f7e8SFlorian Hahn     else
146fd93a5e3SFlorian Hahn       return DefR && DefR->getOpcode() == Opcode;
147fd93a5e3SFlorian Hahn   }
148fd93a5e3SFlorian Hahn };
149fd93a5e3SFlorian Hahn 
150fd93a5e3SFlorian Hahn template <unsigned Opcode, typename RecipeTy, typename... RecipeTys>
151fd93a5e3SFlorian Hahn struct MatchRecipeAndOpcode<Opcode, RecipeTy, RecipeTys...> {
152fd93a5e3SFlorian Hahn   static bool match(const VPRecipeBase *R) {
153fd93a5e3SFlorian Hahn     return MatchRecipeAndOpcode<Opcode, RecipeTy>::match(R) ||
154fd93a5e3SFlorian Hahn            MatchRecipeAndOpcode<Opcode, RecipeTys...>::match(R);
155fd93a5e3SFlorian Hahn   }
156fd93a5e3SFlorian Hahn };
157dac0f7e8SFlorian Hahn template <typename TupleTy, typename Fn, std::size_t... Is>
158dac0f7e8SFlorian Hahn bool CheckTupleElements(const TupleTy &Ops, Fn P, std::index_sequence<Is...>) {
159dac0f7e8SFlorian Hahn   return (P(std::get<Is>(Ops), Is) && ...);
160dac0f7e8SFlorian Hahn }
161dac0f7e8SFlorian Hahn 
162dac0f7e8SFlorian Hahn /// Helper to check if predicate \p P holds on all tuple elements in \p Ops
163dac0f7e8SFlorian Hahn template <typename TupleTy, typename Fn>
164dac0f7e8SFlorian Hahn bool all_of_tuple_elements(const TupleTy &Ops, Fn P) {
165dac0f7e8SFlorian Hahn   return CheckTupleElements(
166dac0f7e8SFlorian Hahn       Ops, P, std::make_index_sequence<std::tuple_size<TupleTy>::value>{});
167dac0f7e8SFlorian Hahn }
168fd93a5e3SFlorian Hahn } // namespace detail
169fd93a5e3SFlorian Hahn 
170dac0f7e8SFlorian Hahn template <typename Ops_t, unsigned Opcode, bool Commutative,
171dac0f7e8SFlorian Hahn           typename... RecipeTys>
172dac0f7e8SFlorian Hahn struct Recipe_match {
173dac0f7e8SFlorian Hahn   Ops_t Ops;
1742435dcd8SFlorian Hahn 
175dac0f7e8SFlorian Hahn   Recipe_match() : Ops() {
176dac0f7e8SFlorian Hahn     static_assert(std::tuple_size<Ops_t>::value == 0 &&
177dac0f7e8SFlorian Hahn                   "constructor can only be used with zero operands");
178dac0f7e8SFlorian Hahn   }
179dac0f7e8SFlorian Hahn   Recipe_match(Ops_t Ops) : Ops(Ops) {}
180dac0f7e8SFlorian Hahn   template <typename A_t, typename B_t>
181dac0f7e8SFlorian Hahn   Recipe_match(A_t A, B_t B) : Ops({A, B}) {
182dac0f7e8SFlorian Hahn     static_assert(std::tuple_size<Ops_t>::value == 2 &&
183dac0f7e8SFlorian Hahn                   "constructor can only be used for binary matcher");
184dac0f7e8SFlorian Hahn   }
1852435dcd8SFlorian Hahn 
18628047750SRamkumar Ramachandra   bool match(const VPValue *V) const {
1872435dcd8SFlorian Hahn     auto *DefR = V->getDefiningRecipe();
1882435dcd8SFlorian Hahn     return DefR && match(DefR);
1892435dcd8SFlorian Hahn   }
1902435dcd8SFlorian Hahn 
19128047750SRamkumar Ramachandra   bool match(const VPSingleDefRecipe *R) const {
1928ec40675SFlorian Hahn     return match(static_cast<const VPRecipeBase *>(R));
1938ec40675SFlorian Hahn   }
1948ec40675SFlorian Hahn 
19528047750SRamkumar Ramachandra   bool match(const VPRecipeBase *R) const {
196fd93a5e3SFlorian Hahn     if (!detail::MatchRecipeAndOpcode<Opcode, RecipeTys...>::match(R))
1972435dcd8SFlorian Hahn       return false;
198dac0f7e8SFlorian Hahn     assert(R->getNumOperands() == std::tuple_size<Ops_t>::value &&
199dac0f7e8SFlorian Hahn            "recipe with matched opcode the expected number of operands");
200dac0f7e8SFlorian Hahn 
201dac0f7e8SFlorian Hahn     if (detail::all_of_tuple_elements(Ops, [R](auto Op, unsigned Idx) {
202dac0f7e8SFlorian Hahn           return Op.match(R->getOperand(Idx));
203dac0f7e8SFlorian Hahn         }))
204dac0f7e8SFlorian Hahn       return true;
205dac0f7e8SFlorian Hahn 
206dac0f7e8SFlorian Hahn     return Commutative &&
207dac0f7e8SFlorian Hahn            detail::all_of_tuple_elements(Ops, [R](auto Op, unsigned Idx) {
208dac0f7e8SFlorian Hahn              return Op.match(R->getOperand(R->getNumOperands() - Idx - 1));
209dac0f7e8SFlorian Hahn            });
210fd93a5e3SFlorian Hahn   }
211fd93a5e3SFlorian Hahn };
212fd93a5e3SFlorian Hahn 
213dac0f7e8SFlorian Hahn template <typename Op0_t, unsigned Opcode, typename... RecipeTys>
214dac0f7e8SFlorian Hahn using UnaryRecipe_match =
215dac0f7e8SFlorian Hahn     Recipe_match<std::tuple<Op0_t>, Opcode, false, RecipeTys...>;
216dac0f7e8SFlorian Hahn 
217fd93a5e3SFlorian Hahn template <typename Op0_t, unsigned Opcode>
218fd93a5e3SFlorian Hahn using UnaryVPInstruction_match =
219fd93a5e3SFlorian Hahn     UnaryRecipe_match<Op0_t, Opcode, VPInstruction>;
220fd93a5e3SFlorian Hahn 
221fd93a5e3SFlorian Hahn template <typename Op0_t, unsigned Opcode>
222fd93a5e3SFlorian Hahn using AllUnaryRecipe_match =
223fd93a5e3SFlorian Hahn     UnaryRecipe_match<Op0_t, Opcode, VPWidenRecipe, VPReplicateRecipe,
224fd93a5e3SFlorian Hahn                       VPWidenCastRecipe, VPInstruction>;
225fd93a5e3SFlorian Hahn 
22682c5d350SFlorian Hahn template <typename Op0_t, typename Op1_t, unsigned Opcode, bool Commutative,
227fd93a5e3SFlorian Hahn           typename... RecipeTys>
228dac0f7e8SFlorian Hahn using BinaryRecipe_match =
229dac0f7e8SFlorian Hahn     Recipe_match<std::tuple<Op0_t, Op1_t>, Opcode, Commutative, RecipeTys...>;
2302435dcd8SFlorian Hahn 
2312435dcd8SFlorian Hahn template <typename Op0_t, typename Op1_t, unsigned Opcode>
232fd93a5e3SFlorian Hahn using BinaryVPInstruction_match =
23382c5d350SFlorian Hahn     BinaryRecipe_match<Op0_t, Op1_t, Opcode, /*Commutative*/ false,
23482c5d350SFlorian Hahn                        VPInstruction>;
2352435dcd8SFlorian Hahn 
23682c5d350SFlorian Hahn template <typename Op0_t, typename Op1_t, unsigned Opcode,
23782c5d350SFlorian Hahn           bool Commutative = false>
238fd93a5e3SFlorian Hahn using AllBinaryRecipe_match =
23982c5d350SFlorian Hahn     BinaryRecipe_match<Op0_t, Op1_t, Opcode, Commutative, VPWidenRecipe,
24082c5d350SFlorian Hahn                        VPReplicateRecipe, VPWidenCastRecipe, VPInstruction>;
2412435dcd8SFlorian Hahn 
2422435dcd8SFlorian Hahn template <unsigned Opcode, typename Op0_t>
2432435dcd8SFlorian Hahn inline UnaryVPInstruction_match<Op0_t, Opcode>
2442435dcd8SFlorian Hahn m_VPInstruction(const Op0_t &Op0) {
2452435dcd8SFlorian Hahn   return UnaryVPInstruction_match<Op0_t, Opcode>(Op0);
2462435dcd8SFlorian Hahn }
2472435dcd8SFlorian Hahn 
2482435dcd8SFlorian Hahn template <unsigned Opcode, typename Op0_t, typename Op1_t>
2492435dcd8SFlorian Hahn inline BinaryVPInstruction_match<Op0_t, Op1_t, Opcode>
2502435dcd8SFlorian Hahn m_VPInstruction(const Op0_t &Op0, const Op1_t &Op1) {
2512435dcd8SFlorian Hahn   return BinaryVPInstruction_match<Op0_t, Op1_t, Opcode>(Op0, Op1);
2522435dcd8SFlorian Hahn }
2532435dcd8SFlorian Hahn 
2542435dcd8SFlorian Hahn template <typename Op0_t>
2552435dcd8SFlorian Hahn inline UnaryVPInstruction_match<Op0_t, VPInstruction::Not>
2562435dcd8SFlorian Hahn m_Not(const Op0_t &Op0) {
2572435dcd8SFlorian Hahn   return m_VPInstruction<VPInstruction::Not>(Op0);
2582435dcd8SFlorian Hahn }
2592435dcd8SFlorian Hahn 
2602435dcd8SFlorian Hahn template <typename Op0_t>
2612435dcd8SFlorian Hahn inline UnaryVPInstruction_match<Op0_t, VPInstruction::BranchOnCond>
2622435dcd8SFlorian Hahn m_BranchOnCond(const Op0_t &Op0) {
2632435dcd8SFlorian Hahn   return m_VPInstruction<VPInstruction::BranchOnCond>(Op0);
2642435dcd8SFlorian Hahn }
2652435dcd8SFlorian Hahn 
2662435dcd8SFlorian Hahn template <typename Op0_t, typename Op1_t>
2672435dcd8SFlorian Hahn inline BinaryVPInstruction_match<Op0_t, Op1_t, VPInstruction::ActiveLaneMask>
2682435dcd8SFlorian Hahn m_ActiveLaneMask(const Op0_t &Op0, const Op1_t &Op1) {
2692435dcd8SFlorian Hahn   return m_VPInstruction<VPInstruction::ActiveLaneMask>(Op0, Op1);
2702435dcd8SFlorian Hahn }
2712435dcd8SFlorian Hahn 
2722435dcd8SFlorian Hahn template <typename Op0_t, typename Op1_t>
2732435dcd8SFlorian Hahn inline BinaryVPInstruction_match<Op0_t, Op1_t, VPInstruction::BranchOnCount>
2742435dcd8SFlorian Hahn m_BranchOnCount(const Op0_t &Op0, const Op1_t &Op1) {
2752435dcd8SFlorian Hahn   return m_VPInstruction<VPInstruction::BranchOnCount>(Op0, Op1);
2762435dcd8SFlorian Hahn }
277fd93a5e3SFlorian Hahn 
278fd93a5e3SFlorian Hahn template <unsigned Opcode, typename Op0_t>
279fd93a5e3SFlorian Hahn inline AllUnaryRecipe_match<Op0_t, Opcode> m_Unary(const Op0_t &Op0) {
280fd93a5e3SFlorian Hahn   return AllUnaryRecipe_match<Op0_t, Opcode>(Op0);
281fd93a5e3SFlorian Hahn }
282fd93a5e3SFlorian Hahn 
283fd93a5e3SFlorian Hahn template <typename Op0_t>
284fd93a5e3SFlorian Hahn inline AllUnaryRecipe_match<Op0_t, Instruction::Trunc>
285fd93a5e3SFlorian Hahn m_Trunc(const Op0_t &Op0) {
286fd93a5e3SFlorian Hahn   return m_Unary<Instruction::Trunc, Op0_t>(Op0);
287fd93a5e3SFlorian Hahn }
288fd93a5e3SFlorian Hahn 
289fd93a5e3SFlorian Hahn template <typename Op0_t>
290fd93a5e3SFlorian Hahn inline AllUnaryRecipe_match<Op0_t, Instruction::ZExt> m_ZExt(const Op0_t &Op0) {
291fd93a5e3SFlorian Hahn   return m_Unary<Instruction::ZExt, Op0_t>(Op0);
292fd93a5e3SFlorian Hahn }
293fd93a5e3SFlorian Hahn 
294fd93a5e3SFlorian Hahn template <typename Op0_t>
295fd93a5e3SFlorian Hahn inline AllUnaryRecipe_match<Op0_t, Instruction::SExt> m_SExt(const Op0_t &Op0) {
296fd93a5e3SFlorian Hahn   return m_Unary<Instruction::SExt, Op0_t>(Op0);
297fd93a5e3SFlorian Hahn }
298fd93a5e3SFlorian Hahn 
299fd93a5e3SFlorian Hahn template <typename Op0_t>
300fd93a5e3SFlorian Hahn inline match_combine_or<AllUnaryRecipe_match<Op0_t, Instruction::ZExt>,
301fd93a5e3SFlorian Hahn                         AllUnaryRecipe_match<Op0_t, Instruction::SExt>>
302fd93a5e3SFlorian Hahn m_ZExtOrSExt(const Op0_t &Op0) {
303fd93a5e3SFlorian Hahn   return m_CombineOr(m_ZExt(Op0), m_SExt(Op0));
304fd93a5e3SFlorian Hahn }
305fd93a5e3SFlorian Hahn 
30682c5d350SFlorian Hahn template <unsigned Opcode, typename Op0_t, typename Op1_t,
30782c5d350SFlorian Hahn           bool Commutative = false>
30882c5d350SFlorian Hahn inline AllBinaryRecipe_match<Op0_t, Op1_t, Opcode, Commutative>
30982c5d350SFlorian Hahn m_Binary(const Op0_t &Op0, const Op1_t &Op1) {
31082c5d350SFlorian Hahn   return AllBinaryRecipe_match<Op0_t, Op1_t, Opcode, Commutative>(Op0, Op1);
311fd93a5e3SFlorian Hahn }
312fd93a5e3SFlorian Hahn 
313*df4a615cSFlorian Hahn template <unsigned Opcode, typename Op0_t, typename Op1_t>
314*df4a615cSFlorian Hahn inline AllBinaryRecipe_match<Op0_t, Op1_t, Opcode, true>
315*df4a615cSFlorian Hahn m_c_Binary(const Op0_t &Op0, const Op1_t &Op1) {
316*df4a615cSFlorian Hahn   return AllBinaryRecipe_match<Op0_t, Op1_t, Opcode, true>(Op0, Op1);
317*df4a615cSFlorian Hahn }
318*df4a615cSFlorian Hahn 
319fd93a5e3SFlorian Hahn template <typename Op0_t, typename Op1_t>
320fd93a5e3SFlorian Hahn inline AllBinaryRecipe_match<Op0_t, Op1_t, Instruction::Mul>
321fd93a5e3SFlorian Hahn m_Mul(const Op0_t &Op0, const Op1_t &Op1) {
322fd93a5e3SFlorian Hahn   return m_Binary<Instruction::Mul, Op0_t, Op1_t>(Op0, Op1);
323fd93a5e3SFlorian Hahn }
324fd93a5e3SFlorian Hahn 
3250e743eccSRamkumar Ramachandra template <typename Op0_t, typename Op1_t>
3260e743eccSRamkumar Ramachandra inline AllBinaryRecipe_match<Op0_t, Op1_t, Instruction::Mul,
3270e743eccSRamkumar Ramachandra                              /* Commutative =*/true>
3280e743eccSRamkumar Ramachandra m_c_Mul(const Op0_t &Op0, const Op1_t &Op1) {
3290e743eccSRamkumar Ramachandra   return m_Binary<Instruction::Mul, Op0_t, Op1_t, true>(Op0, Op1);
3300e743eccSRamkumar Ramachandra }
3310e743eccSRamkumar Ramachandra 
33282c5d350SFlorian Hahn /// Match a binary OR operation. Note that while conceptually the operands can
33382c5d350SFlorian Hahn /// be matched commutatively, \p Commutative defaults to false in line with the
33482c5d350SFlorian Hahn /// IR-based pattern matching infrastructure. Use m_c_BinaryOr for a commutative
33582c5d350SFlorian Hahn /// version of the matcher.
33682c5d350SFlorian Hahn template <typename Op0_t, typename Op1_t, bool Commutative = false>
33782c5d350SFlorian Hahn inline AllBinaryRecipe_match<Op0_t, Op1_t, Instruction::Or, Commutative>
338b050048dSFlorian Hahn m_BinaryOr(const Op0_t &Op0, const Op1_t &Op1) {
33982c5d350SFlorian Hahn   return m_Binary<Instruction::Or, Op0_t, Op1_t, Commutative>(Op0, Op1);
34082c5d350SFlorian Hahn }
34182c5d350SFlorian Hahn 
34282c5d350SFlorian Hahn template <typename Op0_t, typename Op1_t>
34382c5d350SFlorian Hahn inline AllBinaryRecipe_match<Op0_t, Op1_t, Instruction::Or,
34482c5d350SFlorian Hahn                              /*Commutative*/ true>
34582c5d350SFlorian Hahn m_c_BinaryOr(const Op0_t &Op0, const Op1_t &Op1) {
34682c5d350SFlorian Hahn   return m_BinaryOr<Op0_t, Op1_t, /*Commutative*/ true>(Op0, Op1);
3476ef82994SFlorian Hahn }
348b050048dSFlorian Hahn 
349*df4a615cSFlorian Hahn template <typename Op0_t, typename Op1_t>
350*df4a615cSFlorian Hahn using GEPLikeRecipe_match =
351*df4a615cSFlorian Hahn     BinaryRecipe_match<Op0_t, Op1_t, Instruction::GetElementPtr, false,
352*df4a615cSFlorian Hahn                        VPWidenRecipe, VPReplicateRecipe, VPWidenGEPRecipe,
353*df4a615cSFlorian Hahn                        VPInstruction>;
354*df4a615cSFlorian Hahn 
355*df4a615cSFlorian Hahn template <typename Op0_t, typename Op1_t>
356*df4a615cSFlorian Hahn inline GEPLikeRecipe_match<Op0_t, Op1_t> m_GetElementPtr(const Op0_t &Op0,
357*df4a615cSFlorian Hahn                                                          const Op1_t &Op1) {
358*df4a615cSFlorian Hahn   return GEPLikeRecipe_match<Op0_t, Op1_t>(Op0, Op1);
359*df4a615cSFlorian Hahn }
360*df4a615cSFlorian Hahn 
3611d9b3222SFlorian Hahn template <typename Op0_t, typename Op1_t, typename Op2_t, unsigned Opcode>
3621d9b3222SFlorian Hahn using AllTernaryRecipe_match =
3631d9b3222SFlorian Hahn     Recipe_match<std::tuple<Op0_t, Op1_t, Op2_t>, Opcode, false,
3641d9b3222SFlorian Hahn                  VPReplicateRecipe, VPInstruction, VPWidenSelectRecipe>;
3651d9b3222SFlorian Hahn 
3661d9b3222SFlorian Hahn template <typename Op0_t, typename Op1_t, typename Op2_t>
3671d9b3222SFlorian Hahn inline AllTernaryRecipe_match<Op0_t, Op1_t, Op2_t, Instruction::Select>
3681d9b3222SFlorian Hahn m_Select(const Op0_t &Op0, const Op1_t &Op1, const Op2_t &Op2) {
3691d9b3222SFlorian Hahn   return AllTernaryRecipe_match<Op0_t, Op1_t, Op2_t, Instruction::Select>(
3701d9b3222SFlorian Hahn       {Op0, Op1, Op2});
3711d9b3222SFlorian Hahn }
3721d9b3222SFlorian Hahn 
373b050048dSFlorian Hahn template <typename Op0_t, typename Op1_t>
3741d9b3222SFlorian Hahn inline match_combine_or<
3751d9b3222SFlorian Hahn     BinaryVPInstruction_match<Op0_t, Op1_t, VPInstruction::LogicalAnd>,
3761d9b3222SFlorian Hahn     AllTernaryRecipe_match<Op0_t, Op1_t, specific_intval<1>,
3771d9b3222SFlorian Hahn                            Instruction::Select>>
378b050048dSFlorian Hahn m_LogicalAnd(const Op0_t &Op0, const Op1_t &Op1) {
3791d9b3222SFlorian Hahn   return m_CombineOr(
3801d9b3222SFlorian Hahn       m_VPInstruction<VPInstruction::LogicalAnd, Op0_t, Op1_t>(Op0, Op1),
3811d9b3222SFlorian Hahn       m_Select(Op0, Op1, m_False()));
3821d9b3222SFlorian Hahn }
3831d9b3222SFlorian Hahn 
3841d9b3222SFlorian Hahn template <typename Op0_t, typename Op1_t>
3851d9b3222SFlorian Hahn inline AllTernaryRecipe_match<Op0_t, specific_intval<1>, Op1_t,
3861d9b3222SFlorian Hahn                               Instruction::Select>
3871d9b3222SFlorian Hahn m_LogicalOr(const Op0_t &Op0, const Op1_t &Op1) {
3881d9b3222SFlorian Hahn   return m_Select(Op0, m_True(), Op1);
389b050048dSFlorian Hahn }
390c008647bSFlorian Hahn 
391dac0f7e8SFlorian Hahn using VPCanonicalIVPHI_match =
392dac0f7e8SFlorian Hahn     Recipe_match<std::tuple<>, 0, false, VPCanonicalIVPHIRecipe>;
393c008647bSFlorian Hahn 
394c008647bSFlorian Hahn inline VPCanonicalIVPHI_match m_CanonicalIV() {
395c008647bSFlorian Hahn   return VPCanonicalIVPHI_match();
396c008647bSFlorian Hahn }
397c008647bSFlorian Hahn 
398dac0f7e8SFlorian Hahn template <typename Op0_t, typename Op1_t>
399dac0f7e8SFlorian Hahn using VPScalarIVSteps_match =
400dac0f7e8SFlorian Hahn     Recipe_match<std::tuple<Op0_t, Op1_t>, 0, false, VPScalarIVStepsRecipe>;
401c008647bSFlorian Hahn 
402c008647bSFlorian Hahn template <typename Op0_t, typename Op1_t>
403c008647bSFlorian Hahn inline VPScalarIVSteps_match<Op0_t, Op1_t> m_ScalarIVSteps(const Op0_t &Op0,
404c008647bSFlorian Hahn                                                            const Op1_t &Op1) {
405c008647bSFlorian Hahn   return VPScalarIVSteps_match<Op0_t, Op1_t>(Op0, Op1);
406c008647bSFlorian Hahn }
407e1833e3aSFlorian Hahn 
408e1833e3aSFlorian Hahn template <typename Op0_t, typename Op1_t, typename Op2_t>
409e1833e3aSFlorian Hahn using VPDerivedIV_match =
410e1833e3aSFlorian Hahn     Recipe_match<std::tuple<Op0_t, Op1_t, Op2_t>, 0, false, VPDerivedIVRecipe>;
411e1833e3aSFlorian Hahn 
412e1833e3aSFlorian Hahn template <typename Op0_t, typename Op1_t, typename Op2_t>
413e1833e3aSFlorian Hahn inline VPDerivedIV_match<Op0_t, Op1_t, Op2_t>
414e1833e3aSFlorian Hahn m_DerivedIV(const Op0_t &Op0, const Op1_t &Op1, const Op2_t &Op2) {
415e1833e3aSFlorian Hahn   return VPDerivedIV_match<Op0_t, Op1_t, Op2_t>({Op0, Op1, Op2});
416e1833e3aSFlorian Hahn }
417e1833e3aSFlorian Hahn 
4182435dcd8SFlorian Hahn } // namespace VPlanPatternMatch
4192435dcd8SFlorian Hahn } // namespace llvm
4202435dcd8SFlorian Hahn 
4212435dcd8SFlorian Hahn #endif
422