xref: /freebsd-src/contrib/llvm-project/llvm/lib/Transforms/Vectorize/VPlanPatternMatch.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1*0fca6ea1SDimitry Andric //===- VPlanPatternMatch.h - Match on VPValues and recipes ------*- C++ -*-===//
2*0fca6ea1SDimitry Andric //
3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0fca6ea1SDimitry Andric //
7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
8*0fca6ea1SDimitry Andric //
9*0fca6ea1SDimitry Andric // This file provides a simple and efficient mechanism for performing general
10*0fca6ea1SDimitry Andric // tree-based pattern matches on the VPlan values and recipes, based on
11*0fca6ea1SDimitry Andric // LLVM's IR pattern matchers.
12*0fca6ea1SDimitry Andric //
13*0fca6ea1SDimitry Andric // Currently it provides generic matchers for unary and binary VPInstructions,
14*0fca6ea1SDimitry Andric // and specialized matchers like m_Not, m_ActiveLaneMask, m_BranchOnCond,
15*0fca6ea1SDimitry Andric // m_BranchOnCount to match specific VPInstructions.
16*0fca6ea1SDimitry Andric // TODO: Add missing matchers for additional opcodes and recipes as needed.
17*0fca6ea1SDimitry Andric //
18*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
19*0fca6ea1SDimitry Andric 
20*0fca6ea1SDimitry Andric #ifndef LLVM_TRANSFORM_VECTORIZE_VPLANPATTERNMATCH_H
21*0fca6ea1SDimitry Andric #define LLVM_TRANSFORM_VECTORIZE_VPLANPATTERNMATCH_H
22*0fca6ea1SDimitry Andric 
23*0fca6ea1SDimitry Andric #include "VPlan.h"
24*0fca6ea1SDimitry Andric 
25*0fca6ea1SDimitry Andric namespace llvm {
26*0fca6ea1SDimitry Andric namespace VPlanPatternMatch {
27*0fca6ea1SDimitry Andric 
28*0fca6ea1SDimitry Andric template <typename Val, typename Pattern> bool match(Val *V, const Pattern &P) {
29*0fca6ea1SDimitry Andric   return const_cast<Pattern &>(P).match(V);
30*0fca6ea1SDimitry Andric }
31*0fca6ea1SDimitry Andric 
32*0fca6ea1SDimitry Andric template <typename Class> struct class_match {
33*0fca6ea1SDimitry Andric   template <typename ITy> bool match(ITy *V) { return isa<Class>(V); }
34*0fca6ea1SDimitry Andric };
35*0fca6ea1SDimitry Andric 
36*0fca6ea1SDimitry Andric /// Match an arbitrary VPValue and ignore it.
37*0fca6ea1SDimitry Andric inline class_match<VPValue> m_VPValue() { return class_match<VPValue>(); }
38*0fca6ea1SDimitry Andric 
39*0fca6ea1SDimitry Andric template <typename Class> struct bind_ty {
40*0fca6ea1SDimitry Andric   Class *&VR;
41*0fca6ea1SDimitry Andric 
42*0fca6ea1SDimitry Andric   bind_ty(Class *&V) : VR(V) {}
43*0fca6ea1SDimitry Andric 
44*0fca6ea1SDimitry Andric   template <typename ITy> bool match(ITy *V) {
45*0fca6ea1SDimitry Andric     if (auto *CV = dyn_cast<Class>(V)) {
46*0fca6ea1SDimitry Andric       VR = CV;
47*0fca6ea1SDimitry Andric       return true;
48*0fca6ea1SDimitry Andric     }
49*0fca6ea1SDimitry Andric     return false;
50*0fca6ea1SDimitry Andric   }
51*0fca6ea1SDimitry Andric };
52*0fca6ea1SDimitry Andric 
53*0fca6ea1SDimitry Andric /// Match a specified integer value or vector of all elements of that
54*0fca6ea1SDimitry Andric /// value. \p BitWidth optionally specifies the bitwidth the matched constant
55*0fca6ea1SDimitry Andric /// must have. If it is 0, the matched constant can have any bitwidth.
56*0fca6ea1SDimitry Andric template <unsigned BitWidth = 0> struct specific_intval {
57*0fca6ea1SDimitry Andric   APInt Val;
58*0fca6ea1SDimitry Andric 
59*0fca6ea1SDimitry Andric   specific_intval(APInt V) : Val(std::move(V)) {}
60*0fca6ea1SDimitry Andric 
61*0fca6ea1SDimitry Andric   bool match(VPValue *VPV) {
62*0fca6ea1SDimitry Andric     if (!VPV->isLiveIn())
63*0fca6ea1SDimitry Andric       return false;
64*0fca6ea1SDimitry Andric     Value *V = VPV->getLiveInIRValue();
65*0fca6ea1SDimitry Andric     const auto *CI = dyn_cast<ConstantInt>(V);
66*0fca6ea1SDimitry Andric     if (!CI && V->getType()->isVectorTy())
67*0fca6ea1SDimitry Andric       if (const auto *C = dyn_cast<Constant>(V))
68*0fca6ea1SDimitry Andric         CI = dyn_cast_or_null<ConstantInt>(
69*0fca6ea1SDimitry Andric             C->getSplatValue(/*AllowPoison=*/false));
70*0fca6ea1SDimitry Andric     if (!CI)
71*0fca6ea1SDimitry Andric       return false;
72*0fca6ea1SDimitry Andric 
73*0fca6ea1SDimitry Andric     assert((BitWidth == 0 || CI->getBitWidth() == BitWidth) &&
74*0fca6ea1SDimitry Andric            "Trying the match constant with unexpected bitwidth.");
75*0fca6ea1SDimitry Andric     return APInt::isSameValue(CI->getValue(), Val);
76*0fca6ea1SDimitry Andric   }
77*0fca6ea1SDimitry Andric };
78*0fca6ea1SDimitry Andric 
79*0fca6ea1SDimitry Andric inline specific_intval<0> m_SpecificInt(uint64_t V) {
80*0fca6ea1SDimitry Andric   return specific_intval<0>(APInt(64, V));
81*0fca6ea1SDimitry Andric }
82*0fca6ea1SDimitry Andric 
83*0fca6ea1SDimitry Andric inline specific_intval<1> m_False() { return specific_intval<1>(APInt(64, 0)); }
84*0fca6ea1SDimitry Andric 
85*0fca6ea1SDimitry Andric /// Matching combinators
86*0fca6ea1SDimitry Andric template <typename LTy, typename RTy> struct match_combine_or {
87*0fca6ea1SDimitry Andric   LTy L;
88*0fca6ea1SDimitry Andric   RTy R;
89*0fca6ea1SDimitry Andric 
90*0fca6ea1SDimitry Andric   match_combine_or(const LTy &Left, const RTy &Right) : L(Left), R(Right) {}
91*0fca6ea1SDimitry Andric 
92*0fca6ea1SDimitry Andric   template <typename ITy> bool match(ITy *V) {
93*0fca6ea1SDimitry Andric     if (L.match(V))
94*0fca6ea1SDimitry Andric       return true;
95*0fca6ea1SDimitry Andric     if (R.match(V))
96*0fca6ea1SDimitry Andric       return true;
97*0fca6ea1SDimitry Andric     return false;
98*0fca6ea1SDimitry Andric   }
99*0fca6ea1SDimitry Andric };
100*0fca6ea1SDimitry Andric 
101*0fca6ea1SDimitry Andric template <typename LTy, typename RTy>
102*0fca6ea1SDimitry Andric inline match_combine_or<LTy, RTy> m_CombineOr(const LTy &L, const RTy &R) {
103*0fca6ea1SDimitry Andric   return match_combine_or<LTy, RTy>(L, R);
104*0fca6ea1SDimitry Andric }
105*0fca6ea1SDimitry Andric 
106*0fca6ea1SDimitry Andric /// Match a VPValue, capturing it if we match.
107*0fca6ea1SDimitry Andric inline bind_ty<VPValue> m_VPValue(VPValue *&V) { return V; }
108*0fca6ea1SDimitry Andric 
109*0fca6ea1SDimitry Andric namespace detail {
110*0fca6ea1SDimitry Andric 
111*0fca6ea1SDimitry Andric /// A helper to match an opcode against multiple recipe types.
112*0fca6ea1SDimitry Andric template <unsigned Opcode, typename...> struct MatchRecipeAndOpcode {};
113*0fca6ea1SDimitry Andric 
114*0fca6ea1SDimitry Andric template <unsigned Opcode, typename RecipeTy>
115*0fca6ea1SDimitry Andric struct MatchRecipeAndOpcode<Opcode, RecipeTy> {
116*0fca6ea1SDimitry Andric   static bool match(const VPRecipeBase *R) {
117*0fca6ea1SDimitry Andric     auto *DefR = dyn_cast<RecipeTy>(R);
118*0fca6ea1SDimitry Andric     return DefR && DefR->getOpcode() == Opcode;
119*0fca6ea1SDimitry Andric   }
120*0fca6ea1SDimitry Andric };
121*0fca6ea1SDimitry Andric 
122*0fca6ea1SDimitry Andric template <unsigned Opcode, typename RecipeTy, typename... RecipeTys>
123*0fca6ea1SDimitry Andric struct MatchRecipeAndOpcode<Opcode, RecipeTy, RecipeTys...> {
124*0fca6ea1SDimitry Andric   static bool match(const VPRecipeBase *R) {
125*0fca6ea1SDimitry Andric     return MatchRecipeAndOpcode<Opcode, RecipeTy>::match(R) ||
126*0fca6ea1SDimitry Andric            MatchRecipeAndOpcode<Opcode, RecipeTys...>::match(R);
127*0fca6ea1SDimitry Andric   }
128*0fca6ea1SDimitry Andric };
129*0fca6ea1SDimitry Andric } // namespace detail
130*0fca6ea1SDimitry Andric 
131*0fca6ea1SDimitry Andric template <typename Op0_t, unsigned Opcode, typename... RecipeTys>
132*0fca6ea1SDimitry Andric struct UnaryRecipe_match {
133*0fca6ea1SDimitry Andric   Op0_t Op0;
134*0fca6ea1SDimitry Andric 
135*0fca6ea1SDimitry Andric   UnaryRecipe_match(Op0_t Op0) : Op0(Op0) {}
136*0fca6ea1SDimitry Andric 
137*0fca6ea1SDimitry Andric   bool match(const VPValue *V) {
138*0fca6ea1SDimitry Andric     auto *DefR = V->getDefiningRecipe();
139*0fca6ea1SDimitry Andric     return DefR && match(DefR);
140*0fca6ea1SDimitry Andric   }
141*0fca6ea1SDimitry Andric 
142*0fca6ea1SDimitry Andric   bool match(const VPRecipeBase *R) {
143*0fca6ea1SDimitry Andric     if (!detail::MatchRecipeAndOpcode<Opcode, RecipeTys...>::match(R))
144*0fca6ea1SDimitry Andric       return false;
145*0fca6ea1SDimitry Andric     assert(R->getNumOperands() == 1 &&
146*0fca6ea1SDimitry Andric            "recipe with matched opcode does not have 1 operands");
147*0fca6ea1SDimitry Andric     return Op0.match(R->getOperand(0));
148*0fca6ea1SDimitry Andric   }
149*0fca6ea1SDimitry Andric };
150*0fca6ea1SDimitry Andric 
151*0fca6ea1SDimitry Andric template <typename Op0_t, unsigned Opcode>
152*0fca6ea1SDimitry Andric using UnaryVPInstruction_match =
153*0fca6ea1SDimitry Andric     UnaryRecipe_match<Op0_t, Opcode, VPInstruction>;
154*0fca6ea1SDimitry Andric 
155*0fca6ea1SDimitry Andric template <typename Op0_t, unsigned Opcode>
156*0fca6ea1SDimitry Andric using AllUnaryRecipe_match =
157*0fca6ea1SDimitry Andric     UnaryRecipe_match<Op0_t, Opcode, VPWidenRecipe, VPReplicateRecipe,
158*0fca6ea1SDimitry Andric                       VPWidenCastRecipe, VPInstruction>;
159*0fca6ea1SDimitry Andric 
160*0fca6ea1SDimitry Andric template <typename Op0_t, typename Op1_t, unsigned Opcode, bool Commutative,
161*0fca6ea1SDimitry Andric           typename... RecipeTys>
162*0fca6ea1SDimitry Andric struct BinaryRecipe_match {
163*0fca6ea1SDimitry Andric   Op0_t Op0;
164*0fca6ea1SDimitry Andric   Op1_t Op1;
165*0fca6ea1SDimitry Andric 
166*0fca6ea1SDimitry Andric   BinaryRecipe_match(Op0_t Op0, Op1_t Op1) : Op0(Op0), Op1(Op1) {}
167*0fca6ea1SDimitry Andric 
168*0fca6ea1SDimitry Andric   bool match(const VPValue *V) {
169*0fca6ea1SDimitry Andric     auto *DefR = V->getDefiningRecipe();
170*0fca6ea1SDimitry Andric     return DefR && match(DefR);
171*0fca6ea1SDimitry Andric   }
172*0fca6ea1SDimitry Andric 
173*0fca6ea1SDimitry Andric   bool match(const VPSingleDefRecipe *R) {
174*0fca6ea1SDimitry Andric     return match(static_cast<const VPRecipeBase *>(R));
175*0fca6ea1SDimitry Andric   }
176*0fca6ea1SDimitry Andric 
177*0fca6ea1SDimitry Andric   bool match(const VPRecipeBase *R) {
178*0fca6ea1SDimitry Andric     if (!detail::MatchRecipeAndOpcode<Opcode, RecipeTys...>::match(R))
179*0fca6ea1SDimitry Andric       return false;
180*0fca6ea1SDimitry Andric     assert(R->getNumOperands() == 2 &&
181*0fca6ea1SDimitry Andric            "recipe with matched opcode does not have 2 operands");
182*0fca6ea1SDimitry Andric     if (Op0.match(R->getOperand(0)) && Op1.match(R->getOperand(1)))
183*0fca6ea1SDimitry Andric       return true;
184*0fca6ea1SDimitry Andric     return Commutative && Op0.match(R->getOperand(1)) &&
185*0fca6ea1SDimitry Andric            Op1.match(R->getOperand(0));
186*0fca6ea1SDimitry Andric   }
187*0fca6ea1SDimitry Andric };
188*0fca6ea1SDimitry Andric 
189*0fca6ea1SDimitry Andric template <typename Op0_t, typename Op1_t, unsigned Opcode>
190*0fca6ea1SDimitry Andric using BinaryVPInstruction_match =
191*0fca6ea1SDimitry Andric     BinaryRecipe_match<Op0_t, Op1_t, Opcode, /*Commutative*/ false,
192*0fca6ea1SDimitry Andric                        VPInstruction>;
193*0fca6ea1SDimitry Andric 
194*0fca6ea1SDimitry Andric template <typename Op0_t, typename Op1_t, unsigned Opcode,
195*0fca6ea1SDimitry Andric           bool Commutative = false>
196*0fca6ea1SDimitry Andric using AllBinaryRecipe_match =
197*0fca6ea1SDimitry Andric     BinaryRecipe_match<Op0_t, Op1_t, Opcode, Commutative, VPWidenRecipe,
198*0fca6ea1SDimitry Andric                        VPReplicateRecipe, VPWidenCastRecipe, VPInstruction>;
199*0fca6ea1SDimitry Andric 
200*0fca6ea1SDimitry Andric template <unsigned Opcode, typename Op0_t>
201*0fca6ea1SDimitry Andric inline UnaryVPInstruction_match<Op0_t, Opcode>
202*0fca6ea1SDimitry Andric m_VPInstruction(const Op0_t &Op0) {
203*0fca6ea1SDimitry Andric   return UnaryVPInstruction_match<Op0_t, Opcode>(Op0);
204*0fca6ea1SDimitry Andric }
205*0fca6ea1SDimitry Andric 
206*0fca6ea1SDimitry Andric template <unsigned Opcode, typename Op0_t, typename Op1_t>
207*0fca6ea1SDimitry Andric inline BinaryVPInstruction_match<Op0_t, Op1_t, Opcode>
208*0fca6ea1SDimitry Andric m_VPInstruction(const Op0_t &Op0, const Op1_t &Op1) {
209*0fca6ea1SDimitry Andric   return BinaryVPInstruction_match<Op0_t, Op1_t, Opcode>(Op0, Op1);
210*0fca6ea1SDimitry Andric }
211*0fca6ea1SDimitry Andric 
212*0fca6ea1SDimitry Andric template <typename Op0_t>
213*0fca6ea1SDimitry Andric inline UnaryVPInstruction_match<Op0_t, VPInstruction::Not>
214*0fca6ea1SDimitry Andric m_Not(const Op0_t &Op0) {
215*0fca6ea1SDimitry Andric   return m_VPInstruction<VPInstruction::Not>(Op0);
216*0fca6ea1SDimitry Andric }
217*0fca6ea1SDimitry Andric 
218*0fca6ea1SDimitry Andric template <typename Op0_t>
219*0fca6ea1SDimitry Andric inline UnaryVPInstruction_match<Op0_t, VPInstruction::BranchOnCond>
220*0fca6ea1SDimitry Andric m_BranchOnCond(const Op0_t &Op0) {
221*0fca6ea1SDimitry Andric   return m_VPInstruction<VPInstruction::BranchOnCond>(Op0);
222*0fca6ea1SDimitry Andric }
223*0fca6ea1SDimitry Andric 
224*0fca6ea1SDimitry Andric template <typename Op0_t, typename Op1_t>
225*0fca6ea1SDimitry Andric inline BinaryVPInstruction_match<Op0_t, Op1_t, VPInstruction::ActiveLaneMask>
226*0fca6ea1SDimitry Andric m_ActiveLaneMask(const Op0_t &Op0, const Op1_t &Op1) {
227*0fca6ea1SDimitry Andric   return m_VPInstruction<VPInstruction::ActiveLaneMask>(Op0, Op1);
228*0fca6ea1SDimitry Andric }
229*0fca6ea1SDimitry Andric 
230*0fca6ea1SDimitry Andric template <typename Op0_t, typename Op1_t>
231*0fca6ea1SDimitry Andric inline BinaryVPInstruction_match<Op0_t, Op1_t, VPInstruction::BranchOnCount>
232*0fca6ea1SDimitry Andric m_BranchOnCount(const Op0_t &Op0, const Op1_t &Op1) {
233*0fca6ea1SDimitry Andric   return m_VPInstruction<VPInstruction::BranchOnCount>(Op0, Op1);
234*0fca6ea1SDimitry Andric }
235*0fca6ea1SDimitry Andric 
236*0fca6ea1SDimitry Andric template <unsigned Opcode, typename Op0_t>
237*0fca6ea1SDimitry Andric inline AllUnaryRecipe_match<Op0_t, Opcode> m_Unary(const Op0_t &Op0) {
238*0fca6ea1SDimitry Andric   return AllUnaryRecipe_match<Op0_t, Opcode>(Op0);
239*0fca6ea1SDimitry Andric }
240*0fca6ea1SDimitry Andric 
241*0fca6ea1SDimitry Andric template <typename Op0_t>
242*0fca6ea1SDimitry Andric inline AllUnaryRecipe_match<Op0_t, Instruction::Trunc>
243*0fca6ea1SDimitry Andric m_Trunc(const Op0_t &Op0) {
244*0fca6ea1SDimitry Andric   return m_Unary<Instruction::Trunc, Op0_t>(Op0);
245*0fca6ea1SDimitry Andric }
246*0fca6ea1SDimitry Andric 
247*0fca6ea1SDimitry Andric template <typename Op0_t>
248*0fca6ea1SDimitry Andric inline AllUnaryRecipe_match<Op0_t, Instruction::ZExt> m_ZExt(const Op0_t &Op0) {
249*0fca6ea1SDimitry Andric   return m_Unary<Instruction::ZExt, Op0_t>(Op0);
250*0fca6ea1SDimitry Andric }
251*0fca6ea1SDimitry Andric 
252*0fca6ea1SDimitry Andric template <typename Op0_t>
253*0fca6ea1SDimitry Andric inline AllUnaryRecipe_match<Op0_t, Instruction::SExt> m_SExt(const Op0_t &Op0) {
254*0fca6ea1SDimitry Andric   return m_Unary<Instruction::SExt, Op0_t>(Op0);
255*0fca6ea1SDimitry Andric }
256*0fca6ea1SDimitry Andric 
257*0fca6ea1SDimitry Andric template <typename Op0_t>
258*0fca6ea1SDimitry Andric inline match_combine_or<AllUnaryRecipe_match<Op0_t, Instruction::ZExt>,
259*0fca6ea1SDimitry Andric                         AllUnaryRecipe_match<Op0_t, Instruction::SExt>>
260*0fca6ea1SDimitry Andric m_ZExtOrSExt(const Op0_t &Op0) {
261*0fca6ea1SDimitry Andric   return m_CombineOr(m_ZExt(Op0), m_SExt(Op0));
262*0fca6ea1SDimitry Andric }
263*0fca6ea1SDimitry Andric 
264*0fca6ea1SDimitry Andric template <unsigned Opcode, typename Op0_t, typename Op1_t,
265*0fca6ea1SDimitry Andric           bool Commutative = false>
266*0fca6ea1SDimitry Andric inline AllBinaryRecipe_match<Op0_t, Op1_t, Opcode, Commutative>
267*0fca6ea1SDimitry Andric m_Binary(const Op0_t &Op0, const Op1_t &Op1) {
268*0fca6ea1SDimitry Andric   return AllBinaryRecipe_match<Op0_t, Op1_t, Opcode, Commutative>(Op0, Op1);
269*0fca6ea1SDimitry Andric }
270*0fca6ea1SDimitry Andric 
271*0fca6ea1SDimitry Andric template <typename Op0_t, typename Op1_t>
272*0fca6ea1SDimitry Andric inline AllBinaryRecipe_match<Op0_t, Op1_t, Instruction::Mul>
273*0fca6ea1SDimitry Andric m_Mul(const Op0_t &Op0, const Op1_t &Op1) {
274*0fca6ea1SDimitry Andric   return m_Binary<Instruction::Mul, Op0_t, Op1_t>(Op0, Op1);
275*0fca6ea1SDimitry Andric }
276*0fca6ea1SDimitry Andric 
277*0fca6ea1SDimitry Andric template <typename Op0_t, typename Op1_t>
278*0fca6ea1SDimitry Andric inline AllBinaryRecipe_match<Op0_t, Op1_t, Instruction::Mul,
279*0fca6ea1SDimitry Andric                              /* Commutative =*/true>
280*0fca6ea1SDimitry Andric m_c_Mul(const Op0_t &Op0, const Op1_t &Op1) {
281*0fca6ea1SDimitry Andric   return m_Binary<Instruction::Mul, Op0_t, Op1_t, true>(Op0, Op1);
282*0fca6ea1SDimitry Andric }
283*0fca6ea1SDimitry Andric 
284*0fca6ea1SDimitry Andric /// Match a binary OR operation. Note that while conceptually the operands can
285*0fca6ea1SDimitry Andric /// be matched commutatively, \p Commutative defaults to false in line with the
286*0fca6ea1SDimitry Andric /// IR-based pattern matching infrastructure. Use m_c_BinaryOr for a commutative
287*0fca6ea1SDimitry Andric /// version of the matcher.
288*0fca6ea1SDimitry Andric template <typename Op0_t, typename Op1_t, bool Commutative = false>
289*0fca6ea1SDimitry Andric inline AllBinaryRecipe_match<Op0_t, Op1_t, Instruction::Or, Commutative>
290*0fca6ea1SDimitry Andric m_BinaryOr(const Op0_t &Op0, const Op1_t &Op1) {
291*0fca6ea1SDimitry Andric   return m_Binary<Instruction::Or, Op0_t, Op1_t, Commutative>(Op0, Op1);
292*0fca6ea1SDimitry Andric }
293*0fca6ea1SDimitry Andric 
294*0fca6ea1SDimitry Andric template <typename Op0_t, typename Op1_t>
295*0fca6ea1SDimitry Andric inline AllBinaryRecipe_match<Op0_t, Op1_t, Instruction::Or,
296*0fca6ea1SDimitry Andric                              /*Commutative*/ true>
297*0fca6ea1SDimitry Andric m_c_BinaryOr(const Op0_t &Op0, const Op1_t &Op1) {
298*0fca6ea1SDimitry Andric   return m_BinaryOr<Op0_t, Op1_t, /*Commutative*/ true>(Op0, Op1);
299*0fca6ea1SDimitry Andric }
300*0fca6ea1SDimitry Andric 
301*0fca6ea1SDimitry Andric template <typename Op0_t, typename Op1_t>
302*0fca6ea1SDimitry Andric inline BinaryVPInstruction_match<Op0_t, Op1_t, VPInstruction::LogicalAnd>
303*0fca6ea1SDimitry Andric m_LogicalAnd(const Op0_t &Op0, const Op1_t &Op1) {
304*0fca6ea1SDimitry Andric   return m_VPInstruction<VPInstruction::LogicalAnd, Op0_t, Op1_t>(Op0, Op1);
305*0fca6ea1SDimitry Andric }
306*0fca6ea1SDimitry Andric 
307*0fca6ea1SDimitry Andric struct VPCanonicalIVPHI_match {
308*0fca6ea1SDimitry Andric   bool match(const VPValue *V) {
309*0fca6ea1SDimitry Andric     auto *DefR = V->getDefiningRecipe();
310*0fca6ea1SDimitry Andric     return DefR && match(DefR);
311*0fca6ea1SDimitry Andric   }
312*0fca6ea1SDimitry Andric 
313*0fca6ea1SDimitry Andric   bool match(const VPRecipeBase *R) { return isa<VPCanonicalIVPHIRecipe>(R); }
314*0fca6ea1SDimitry Andric };
315*0fca6ea1SDimitry Andric 
316*0fca6ea1SDimitry Andric inline VPCanonicalIVPHI_match m_CanonicalIV() {
317*0fca6ea1SDimitry Andric   return VPCanonicalIVPHI_match();
318*0fca6ea1SDimitry Andric }
319*0fca6ea1SDimitry Andric 
320*0fca6ea1SDimitry Andric template <typename Op0_t, typename Op1_t> struct VPScalarIVSteps_match {
321*0fca6ea1SDimitry Andric   Op0_t Op0;
322*0fca6ea1SDimitry Andric   Op1_t Op1;
323*0fca6ea1SDimitry Andric 
324*0fca6ea1SDimitry Andric   VPScalarIVSteps_match(Op0_t Op0, Op1_t Op1) : Op0(Op0), Op1(Op1) {}
325*0fca6ea1SDimitry Andric 
326*0fca6ea1SDimitry Andric   bool match(const VPValue *V) {
327*0fca6ea1SDimitry Andric     auto *DefR = V->getDefiningRecipe();
328*0fca6ea1SDimitry Andric     return DefR && match(DefR);
329*0fca6ea1SDimitry Andric   }
330*0fca6ea1SDimitry Andric 
331*0fca6ea1SDimitry Andric   bool match(const VPRecipeBase *R) {
332*0fca6ea1SDimitry Andric     if (!isa<VPScalarIVStepsRecipe>(R))
333*0fca6ea1SDimitry Andric       return false;
334*0fca6ea1SDimitry Andric     assert(R->getNumOperands() == 2 &&
335*0fca6ea1SDimitry Andric            "VPScalarIVSteps must have exactly 2 operands");
336*0fca6ea1SDimitry Andric     return Op0.match(R->getOperand(0)) && Op1.match(R->getOperand(1));
337*0fca6ea1SDimitry Andric   }
338*0fca6ea1SDimitry Andric };
339*0fca6ea1SDimitry Andric 
340*0fca6ea1SDimitry Andric template <typename Op0_t, typename Op1_t>
341*0fca6ea1SDimitry Andric inline VPScalarIVSteps_match<Op0_t, Op1_t> m_ScalarIVSteps(const Op0_t &Op0,
342*0fca6ea1SDimitry Andric                                                            const Op1_t &Op1) {
343*0fca6ea1SDimitry Andric   return VPScalarIVSteps_match<Op0_t, Op1_t>(Op0, Op1);
344*0fca6ea1SDimitry Andric }
345*0fca6ea1SDimitry Andric 
346*0fca6ea1SDimitry Andric } // namespace VPlanPatternMatch
347*0fca6ea1SDimitry Andric } // namespace llvm
348*0fca6ea1SDimitry Andric 
349*0fca6ea1SDimitry Andric #endif
350