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