1 //===- VPlanPatternMatch.h - Match on VPValues and recipes ------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file provides a simple and efficient mechanism for performing general 10 // tree-based pattern matches on the VPlan values and recipes, based on 11 // LLVM's IR pattern matchers. 12 // 13 // Currently it provides generic matchers for unary and binary VPInstructions, 14 // and specialized matchers like m_Not, m_ActiveLaneMask, m_BranchOnCond, 15 // m_BranchOnCount to match specific VPInstructions. 16 // TODO: Add missing matchers for additional opcodes and recipes as needed. 17 // 18 //===----------------------------------------------------------------------===// 19 20 #ifndef LLVM_TRANSFORM_VECTORIZE_VPLANPATTERNMATCH_H 21 #define LLVM_TRANSFORM_VECTORIZE_VPLANPATTERNMATCH_H 22 23 #include "VPlan.h" 24 25 namespace llvm { 26 namespace VPlanPatternMatch { 27 28 template <typename Val, typename Pattern> bool match(Val *V, const Pattern &P) { 29 return const_cast<Pattern &>(P).match(V); 30 } 31 32 template <typename Class> struct class_match { 33 template <typename ITy> bool match(ITy *V) { return isa<Class>(V); } 34 }; 35 36 /// Match an arbitrary VPValue and ignore it. 37 inline class_match<VPValue> m_VPValue() { return class_match<VPValue>(); } 38 39 template <typename Class> struct bind_ty { 40 Class *&VR; 41 42 bind_ty(Class *&V) : VR(V) {} 43 44 template <typename ITy> bool match(ITy *V) { 45 if (auto *CV = dyn_cast<Class>(V)) { 46 VR = CV; 47 return true; 48 } 49 return false; 50 } 51 }; 52 53 /// Match a specified integer value or vector of all elements of that 54 /// value. 55 struct specific_intval { 56 APInt Val; 57 58 specific_intval(APInt V) : Val(std::move(V)) {} 59 60 bool match(VPValue *VPV) { 61 if (!VPV->isLiveIn()) 62 return false; 63 Value *V = VPV->getLiveInIRValue(); 64 const auto *CI = dyn_cast<ConstantInt>(V); 65 if (!CI && V->getType()->isVectorTy()) 66 if (const auto *C = dyn_cast<Constant>(V)) 67 CI = dyn_cast_or_null<ConstantInt>( 68 C->getSplatValue(/*UndefsAllowed=*/false)); 69 70 return CI && APInt::isSameValue(CI->getValue(), Val); 71 } 72 }; 73 74 inline specific_intval m_SpecificInt(uint64_t V) { 75 return specific_intval(APInt(64, V)); 76 } 77 78 /// Matching combinators 79 template <typename LTy, typename RTy> struct match_combine_or { 80 LTy L; 81 RTy R; 82 83 match_combine_or(const LTy &Left, const RTy &Right) : L(Left), R(Right) {} 84 85 template <typename ITy> bool match(ITy *V) { 86 if (L.match(V)) 87 return true; 88 if (R.match(V)) 89 return true; 90 return false; 91 } 92 }; 93 94 template <typename LTy, typename RTy> 95 inline match_combine_or<LTy, RTy> m_CombineOr(const LTy &L, const RTy &R) { 96 return match_combine_or<LTy, RTy>(L, R); 97 } 98 99 /// Match a VPValue, capturing it if we match. 100 inline bind_ty<VPValue> m_VPValue(VPValue *&V) { return V; } 101 102 namespace detail { 103 104 /// A helper to match an opcode against multiple recipe types. 105 template <unsigned Opcode, typename...> struct MatchRecipeAndOpcode {}; 106 107 template <unsigned Opcode, typename RecipeTy> 108 struct MatchRecipeAndOpcode<Opcode, RecipeTy> { 109 static bool match(const VPRecipeBase *R) { 110 auto *DefR = dyn_cast<RecipeTy>(R); 111 return DefR && DefR->getOpcode() == Opcode; 112 } 113 }; 114 115 template <unsigned Opcode, typename RecipeTy, typename... RecipeTys> 116 struct MatchRecipeAndOpcode<Opcode, RecipeTy, RecipeTys...> { 117 static bool match(const VPRecipeBase *R) { 118 return MatchRecipeAndOpcode<Opcode, RecipeTy>::match(R) || 119 MatchRecipeAndOpcode<Opcode, RecipeTys...>::match(R); 120 } 121 }; 122 } // namespace detail 123 124 template <typename Op0_t, unsigned Opcode, typename... RecipeTys> 125 struct UnaryRecipe_match { 126 Op0_t Op0; 127 128 UnaryRecipe_match(Op0_t Op0) : Op0(Op0) {} 129 130 bool match(const VPValue *V) { 131 auto *DefR = V->getDefiningRecipe(); 132 return DefR && match(DefR); 133 } 134 135 bool match(const VPRecipeBase *R) { 136 if (!detail::MatchRecipeAndOpcode<Opcode, RecipeTys...>::match(R)) 137 return false; 138 assert(R->getNumOperands() == 1 && 139 "recipe with matched opcode does not have 1 operands"); 140 return Op0.match(R->getOperand(0)); 141 } 142 }; 143 144 template <typename Op0_t, unsigned Opcode> 145 using UnaryVPInstruction_match = 146 UnaryRecipe_match<Op0_t, Opcode, VPInstruction>; 147 148 template <typename Op0_t, unsigned Opcode> 149 using AllUnaryRecipe_match = 150 UnaryRecipe_match<Op0_t, Opcode, VPWidenRecipe, VPReplicateRecipe, 151 VPWidenCastRecipe, VPInstruction>; 152 153 template <typename Op0_t, typename Op1_t, unsigned Opcode, 154 typename... RecipeTys> 155 struct BinaryRecipe_match { 156 Op0_t Op0; 157 Op1_t Op1; 158 159 BinaryRecipe_match(Op0_t Op0, Op1_t Op1) : Op0(Op0), Op1(Op1) {} 160 161 bool match(const VPValue *V) { 162 auto *DefR = V->getDefiningRecipe(); 163 return DefR && match(DefR); 164 } 165 166 bool match(const VPSingleDefRecipe *R) { 167 return match(static_cast<const VPRecipeBase *>(R)); 168 } 169 170 bool match(const VPRecipeBase *R) { 171 if (!detail::MatchRecipeAndOpcode<Opcode, RecipeTys...>::match(R)) 172 return false; 173 assert(R->getNumOperands() == 2 && 174 "recipe with matched opcode does not have 2 operands"); 175 return Op0.match(R->getOperand(0)) && Op1.match(R->getOperand(1)); 176 } 177 }; 178 179 template <typename Op0_t, typename Op1_t, unsigned Opcode> 180 using BinaryVPInstruction_match = 181 BinaryRecipe_match<Op0_t, Op1_t, Opcode, VPInstruction>; 182 183 template <typename Op0_t, typename Op1_t, unsigned Opcode> 184 using AllBinaryRecipe_match = 185 BinaryRecipe_match<Op0_t, Op1_t, Opcode, VPWidenRecipe, VPReplicateRecipe, 186 VPWidenCastRecipe, VPInstruction>; 187 188 template <unsigned Opcode, typename Op0_t> 189 inline UnaryVPInstruction_match<Op0_t, Opcode> 190 m_VPInstruction(const Op0_t &Op0) { 191 return UnaryVPInstruction_match<Op0_t, Opcode>(Op0); 192 } 193 194 template <unsigned Opcode, typename Op0_t, typename Op1_t> 195 inline BinaryVPInstruction_match<Op0_t, Op1_t, Opcode> 196 m_VPInstruction(const Op0_t &Op0, const Op1_t &Op1) { 197 return BinaryVPInstruction_match<Op0_t, Op1_t, Opcode>(Op0, Op1); 198 } 199 200 template <typename Op0_t> 201 inline UnaryVPInstruction_match<Op0_t, VPInstruction::Not> 202 m_Not(const Op0_t &Op0) { 203 return m_VPInstruction<VPInstruction::Not>(Op0); 204 } 205 206 template <typename Op0_t> 207 inline UnaryVPInstruction_match<Op0_t, VPInstruction::BranchOnCond> 208 m_BranchOnCond(const Op0_t &Op0) { 209 return m_VPInstruction<VPInstruction::BranchOnCond>(Op0); 210 } 211 212 template <typename Op0_t, typename Op1_t> 213 inline BinaryVPInstruction_match<Op0_t, Op1_t, VPInstruction::ActiveLaneMask> 214 m_ActiveLaneMask(const Op0_t &Op0, const Op1_t &Op1) { 215 return m_VPInstruction<VPInstruction::ActiveLaneMask>(Op0, Op1); 216 } 217 218 template <typename Op0_t, typename Op1_t> 219 inline BinaryVPInstruction_match<Op0_t, Op1_t, VPInstruction::BranchOnCount> 220 m_BranchOnCount(const Op0_t &Op0, const Op1_t &Op1) { 221 return m_VPInstruction<VPInstruction::BranchOnCount>(Op0, Op1); 222 } 223 224 template <unsigned Opcode, typename Op0_t> 225 inline AllUnaryRecipe_match<Op0_t, Opcode> m_Unary(const Op0_t &Op0) { 226 return AllUnaryRecipe_match<Op0_t, Opcode>(Op0); 227 } 228 229 template <typename Op0_t> 230 inline AllUnaryRecipe_match<Op0_t, Instruction::Trunc> 231 m_Trunc(const Op0_t &Op0) { 232 return m_Unary<Instruction::Trunc, Op0_t>(Op0); 233 } 234 235 template <typename Op0_t> 236 inline AllUnaryRecipe_match<Op0_t, Instruction::ZExt> m_ZExt(const Op0_t &Op0) { 237 return m_Unary<Instruction::ZExt, Op0_t>(Op0); 238 } 239 240 template <typename Op0_t> 241 inline AllUnaryRecipe_match<Op0_t, Instruction::SExt> m_SExt(const Op0_t &Op0) { 242 return m_Unary<Instruction::SExt, Op0_t>(Op0); 243 } 244 245 template <typename Op0_t> 246 inline match_combine_or<AllUnaryRecipe_match<Op0_t, Instruction::ZExt>, 247 AllUnaryRecipe_match<Op0_t, Instruction::SExt>> 248 m_ZExtOrSExt(const Op0_t &Op0) { 249 return m_CombineOr(m_ZExt(Op0), m_SExt(Op0)); 250 } 251 252 template <unsigned Opcode, typename Op0_t, typename Op1_t> 253 inline AllBinaryRecipe_match<Op0_t, Op1_t, Opcode> m_Binary(const Op0_t &Op0, 254 const Op1_t &Op1) { 255 return AllBinaryRecipe_match<Op0_t, Op1_t, Opcode>(Op0, Op1); 256 } 257 258 template <typename Op0_t, typename Op1_t> 259 inline AllBinaryRecipe_match<Op0_t, Op1_t, Instruction::Mul> 260 m_Mul(const Op0_t &Op0, const Op1_t &Op1) { 261 return m_Binary<Instruction::Mul, Op0_t, Op1_t>(Op0, Op1); 262 } 263 264 } // namespace VPlanPatternMatch 265 } // namespace llvm 266 267 #endif 268