LLVM 20.0.0git
VPlanPatternMatch.h
Go to the documentation of this file.
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
25namespace llvm {
26namespace VPlanPatternMatch {
27
28template <typename Val, typename Pattern> bool match(Val *V, const Pattern &P) {
29 return const_cast<Pattern &>(P).match(V);
30}
31
32template <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.
38
39template <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. \p BitWidth optionally specifies the bitwidth the matched constant
55/// must have. If it is 0, the matched constant can have any bitwidth.
56template <unsigned BitWidth = 0> struct specific_intval {
58
60
61 bool match(VPValue *VPV) {
62 if (!VPV->isLiveIn())
63 return false;
64 Value *V = VPV->getLiveInIRValue();
65 const auto *CI = dyn_cast<ConstantInt>(V);
66 if (!CI && V->getType()->isVectorTy())
67 if (const auto *C = dyn_cast<Constant>(V))
68 CI = dyn_cast_or_null<ConstantInt>(
69 C->getSplatValue(/*AllowPoison=*/false));
70 if (!CI)
71 return false;
72
73 assert((BitWidth == 0 || CI->getBitWidth() == BitWidth) &&
74 "Trying the match constant with unexpected bitwidth.");
75 return APInt::isSameValue(CI->getValue(), Val);
76 }
77};
78
80 return specific_intval<0>(APInt(64, V));
81}
82
84
85/// Matching combinators
86template <typename LTy, typename RTy> struct match_combine_or {
87 LTy L;
88 RTy R;
89
90 match_combine_or(const LTy &Left, const RTy &Right) : L(Left), R(Right) {}
91
92 template <typename ITy> bool match(ITy *V) {
93 if (L.match(V))
94 return true;
95 if (R.match(V))
96 return true;
97 return false;
98 }
99};
100
101template <typename LTy, typename RTy>
102inline match_combine_or<LTy, RTy> m_CombineOr(const LTy &L, const RTy &R) {
103 return match_combine_or<LTy, RTy>(L, R);
104}
105
106/// Match a VPValue, capturing it if we match.
107inline bind_ty<VPValue> m_VPValue(VPValue *&V) { return V; }
108
109namespace detail {
110
111/// A helper to match an opcode against multiple recipe types.
112template <unsigned Opcode, typename...> struct MatchRecipeAndOpcode {};
113
114template <unsigned Opcode, typename RecipeTy>
116 static bool match(const VPRecipeBase *R) {
117 auto *DefR = dyn_cast<RecipeTy>(R);
118 return DefR && DefR->getOpcode() == Opcode;
119 }
120};
121
122template <unsigned Opcode, typename RecipeTy, typename... RecipeTys>
123struct MatchRecipeAndOpcode<Opcode, RecipeTy, RecipeTys...> {
124 static bool match(const VPRecipeBase *R) {
127 }
128};
129} // namespace detail
130
131template <typename Op0_t, unsigned Opcode, typename... RecipeTys>
133 Op0_t Op0;
134
136
137 bool match(const VPValue *V) {
138 auto *DefR = V->getDefiningRecipe();
139 return DefR && match(DefR);
140 }
141
142 bool match(const VPRecipeBase *R) {
144 return false;
145 assert(R->getNumOperands() == 1 &&
146 "recipe with matched opcode does not have 1 operands");
147 return Op0.match(R->getOperand(0));
148 }
149};
150
151template <typename Op0_t, unsigned Opcode>
154
155template <typename Op0_t, unsigned Opcode>
159
160template <typename Op0_t, typename Op1_t, unsigned Opcode, bool Commutative,
161 typename... RecipeTys>
163 Op0_t Op0;
164 Op1_t Op1;
165
166 BinaryRecipe_match(Op0_t Op0, Op1_t Op1) : Op0(Op0), Op1(Op1) {}
167
168 bool match(const VPValue *V) {
169 auto *DefR = V->getDefiningRecipe();
170 return DefR && match(DefR);
171 }
172
173 bool match(const VPSingleDefRecipe *R) {
174 return match(static_cast<const VPRecipeBase *>(R));
175 }
176
177 bool match(const VPRecipeBase *R) {
179 return false;
180 assert(R->getNumOperands() == 2 &&
181 "recipe with matched opcode does not have 2 operands");
182 if (Op0.match(R->getOperand(0)) && Op1.match(R->getOperand(1)))
183 return true;
184 return Commutative && Op0.match(R->getOperand(1)) &&
185 Op1.match(R->getOperand(0));
186 }
187};
188
189template <typename Op0_t, typename Op1_t, unsigned Opcode>
191 BinaryRecipe_match<Op0_t, Op1_t, Opcode, /*Commutative*/ false,
193
194template <typename Op0_t, typename Op1_t, unsigned Opcode,
195 bool Commutative = false>
197 BinaryRecipe_match<Op0_t, Op1_t, Opcode, Commutative, VPWidenRecipe,
199
200template <unsigned Opcode, typename Op0_t>
202m_VPInstruction(const Op0_t &Op0) {
204}
205
206template <unsigned Opcode, typename Op0_t, typename Op1_t>
207inline BinaryVPInstruction_match<Op0_t, Op1_t, Opcode>
208m_VPInstruction(const Op0_t &Op0, const Op1_t &Op1) {
210}
211
212template <typename Op0_t>
213inline UnaryVPInstruction_match<Op0_t, VPInstruction::Not>
214m_Not(const Op0_t &Op0) {
215 return m_VPInstruction<VPInstruction::Not>(Op0);
216}
217
218template <typename Op0_t>
219inline UnaryVPInstruction_match<Op0_t, VPInstruction::BranchOnCond>
220m_BranchOnCond(const Op0_t &Op0) {
221 return m_VPInstruction<VPInstruction::BranchOnCond>(Op0);
222}
223
224template <typename Op0_t, typename Op1_t>
225inline BinaryVPInstruction_match<Op0_t, Op1_t, VPInstruction::ActiveLaneMask>
226m_ActiveLaneMask(const Op0_t &Op0, const Op1_t &Op1) {
227 return m_VPInstruction<VPInstruction::ActiveLaneMask>(Op0, Op1);
228}
229
230template <typename Op0_t, typename Op1_t>
231inline BinaryVPInstruction_match<Op0_t, Op1_t, VPInstruction::BranchOnCount>
232m_BranchOnCount(const Op0_t &Op0, const Op1_t &Op1) {
233 return m_VPInstruction<VPInstruction::BranchOnCount>(Op0, Op1);
234}
235
236template <unsigned Opcode, typename Op0_t>
239}
240
241template <typename Op0_t>
242inline AllUnaryRecipe_match<Op0_t, Instruction::Trunc>
243m_Trunc(const Op0_t &Op0) {
244 return m_Unary<Instruction::Trunc, Op0_t>(Op0);
245}
246
247template <typename Op0_t>
249 return m_Unary<Instruction::ZExt, Op0_t>(Op0);
250}
251
252template <typename Op0_t>
254 return m_Unary<Instruction::SExt, Op0_t>(Op0);
255}
256
257template <typename Op0_t>
259 AllUnaryRecipe_match<Op0_t, Instruction::SExt>>
260m_ZExtOrSExt(const Op0_t &Op0) {
261 return m_CombineOr(m_ZExt(Op0), m_SExt(Op0));
262}
263
264template <unsigned Opcode, typename Op0_t, typename Op1_t,
265 bool Commutative = false>
266inline AllBinaryRecipe_match<Op0_t, Op1_t, Opcode, Commutative>
267m_Binary(const Op0_t &Op0, const Op1_t &Op1) {
269}
270
271template <typename Op0_t, typename Op1_t>
272inline AllBinaryRecipe_match<Op0_t, Op1_t, Instruction::Mul>
273m_Mul(const Op0_t &Op0, const Op1_t &Op1) {
274 return m_Binary<Instruction::Mul, Op0_t, Op1_t>(Op0, Op1);
275}
276
277template <typename Op0_t, typename Op1_t>
278inline AllBinaryRecipe_match<Op0_t, Op1_t, Instruction::Mul,
279 /* Commutative =*/true>
280m_c_Mul(const Op0_t &Op0, const Op1_t &Op1) {
281 return m_Binary<Instruction::Mul, Op0_t, Op1_t, true>(Op0, Op1);
282}
283
284/// Match a binary OR operation. Note that while conceptually the operands can
285/// be matched commutatively, \p Commutative defaults to false in line with the
286/// IR-based pattern matching infrastructure. Use m_c_BinaryOr for a commutative
287/// version of the matcher.
288template <typename Op0_t, typename Op1_t, bool Commutative = false>
289inline AllBinaryRecipe_match<Op0_t, Op1_t, Instruction::Or, Commutative>
290m_BinaryOr(const Op0_t &Op0, const Op1_t &Op1) {
291 return m_Binary<Instruction::Or, Op0_t, Op1_t, Commutative>(Op0, Op1);
292}
293
294template <typename Op0_t, typename Op1_t>
295inline AllBinaryRecipe_match<Op0_t, Op1_t, Instruction::Or,
296 /*Commutative*/ true>
297m_c_BinaryOr(const Op0_t &Op0, const Op1_t &Op1) {
298 return m_BinaryOr<Op0_t, Op1_t, /*Commutative*/ true>(Op0, Op1);
299}
300
301template <typename Op0_t, typename Op1_t>
302inline BinaryVPInstruction_match<Op0_t, Op1_t, VPInstruction::LogicalAnd>
303m_LogicalAnd(const Op0_t &Op0, const Op1_t &Op1) {
304 return m_VPInstruction<VPInstruction::LogicalAnd, Op0_t, Op1_t>(Op0, Op1);
305}
306
308 bool match(const VPValue *V) {
309 auto *DefR = V->getDefiningRecipe();
310 return DefR && match(DefR);
311 }
312
313 bool match(const VPRecipeBase *R) { return isa<VPCanonicalIVPHIRecipe>(R); }
314};
315
317 return VPCanonicalIVPHI_match();
318}
319
320template <typename Op0_t, typename Op1_t> struct VPScalarIVSteps_match {
321 Op0_t Op0;
322 Op1_t Op1;
323
324 VPScalarIVSteps_match(Op0_t Op0, Op1_t Op1) : Op0(Op0), Op1(Op1) {}
325
326 bool match(const VPValue *V) {
327 auto *DefR = V->getDefiningRecipe();
328 return DefR && match(DefR);
329 }
330
331 bool match(const VPRecipeBase *R) {
332 if (!isa<VPScalarIVStepsRecipe>(R))
333 return false;
334 assert(R->getNumOperands() == 2 &&
335 "VPScalarIVSteps must have exactly 2 operands");
336 return Op0.match(R->getOperand(0)) && Op1.match(R->getOperand(1));
337 }
338};
339
340template <typename Op0_t, typename Op1_t>
342 const Op1_t &Op1) {
344}
345
346} // namespace VPlanPatternMatch
347} // namespace llvm
348
349#endif
#define P(N)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file contains the declarations of the Vectorization Plan base classes:
Class for arbitrary precision integers.
Definition: APInt.h:78
static bool isSameValue(const APInt &I1, const APInt &I2)
Determine if two APInts have the same value, after zero-extending one of them (if needed!...
Definition: APInt.h:533
This is a concrete Recipe that models a single VPlan-level instruction.
Definition: VPlan.h:1229
VPRecipeBase is a base class modeling a sequence of one or more output IR instructions.
Definition: VPlan.h:764
VPReplicateRecipe replicates a given instruction producing multiple scalar copies of the original sca...
Definition: VPlan.h:2296
VPSingleDef is a base class for recipes for modeling a sequence of one or more output IR that define ...
Definition: VPlan.h:891
Value * getLiveInIRValue()
Returns the underlying IR value, if this VPValue is defined outside the scope of VPlan.
Definition: VPlanValue.h:172
bool isLiveIn() const
Returns true if this VPValue is a live-in, i.e. defined outside the VPlan.
Definition: VPlanValue.h:167
VPWidenCastRecipe is a recipe to create vector cast instructions.
Definition: VPlan.h:1439
VPWidenRecipe is a recipe for producing a widened instruction using the opcode and operands of the re...
Definition: VPlan.h:1406
LLVM Value Representation.
Definition: Value.h:74
@ C
The default llvm calling convention, compatible with C.
Definition: CallingConv.h:34
auto m_LogicalAnd()
Matches L && R where L and R are arbitrary values.
AllBinaryRecipe_match< Op0_t, Op1_t, Instruction::Or, Commutative > m_BinaryOr(const Op0_t &Op0, const Op1_t &Op1)
Match a binary OR operation.
AllUnaryRecipe_match< Op0_t, Opcode > m_Unary(const Op0_t &Op0)
AllBinaryRecipe_match< Op0_t, Op1_t, Instruction::Or, true > m_c_BinaryOr(const Op0_t &Op0, const Op1_t &Op1)
BinaryVPInstruction_match< Op0_t, Op1_t, VPInstruction::ActiveLaneMask > m_ActiveLaneMask(const Op0_t &Op0, const Op1_t &Op1)
match_combine_or< LTy, RTy > m_CombineOr(const LTy &L, const RTy &R)
UnaryVPInstruction_match< Op0_t, Opcode > m_VPInstruction(const Op0_t &Op0)
AllBinaryRecipe_match< Op0_t, Op1_t, Opcode, Commutative > m_Binary(const Op0_t &Op0, const Op1_t &Op1)
UnaryVPInstruction_match< Op0_t, VPInstruction::Not > m_Not(const Op0_t &Op0)
VPCanonicalIVPHI_match m_CanonicalIV()
AllUnaryRecipe_match< Op0_t, Instruction::Trunc > m_Trunc(const Op0_t &Op0)
VPScalarIVSteps_match< Op0_t, Op1_t > m_ScalarIVSteps(const Op0_t &Op0, const Op1_t &Op1)
AllBinaryRecipe_match< Op0_t, Op1_t, Instruction::Mul, true > m_c_Mul(const Op0_t &Op0, const Op1_t &Op1)
BinaryVPInstruction_match< Op0_t, Op1_t, VPInstruction::BranchOnCount > m_BranchOnCount(const Op0_t &Op0, const Op1_t &Op1)
specific_intval< 1 > m_False()
specific_intval< 0 > m_SpecificInt(uint64_t V)
AllBinaryRecipe_match< Op0_t, Op1_t, Instruction::Mul > m_Mul(const Op0_t &Op0, const Op1_t &Op1)
UnaryVPInstruction_match< Op0_t, VPInstruction::BranchOnCond > m_BranchOnCond(const Op0_t &Op0)
bool match(Val *V, const Pattern &P)
class_match< VPValue > m_VPValue()
Match an arbitrary VPValue and ignore it.
BinaryRecipe_match< Op0_t, Op1_t, Opcode, Commutative, VPWidenRecipe, VPReplicateRecipe, VPWidenCastRecipe, VPInstruction > AllBinaryRecipe_match
AllUnaryRecipe_match< Op0_t, Instruction::SExt > m_SExt(const Op0_t &Op0)
AllUnaryRecipe_match< Op0_t, Instruction::ZExt > m_ZExt(const Op0_t &Op0)
match_combine_or< AllUnaryRecipe_match< Op0_t, Instruction::ZExt >, AllUnaryRecipe_match< Op0_t, Instruction::SExt > > m_ZExtOrSExt(const Op0_t &Op0)
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
constexpr unsigned BitWidth
Definition: BitmaskEnum.h:191
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1849
Implement std::hash so that hash_code can be used in STL containers.
Definition: BitVector.h:858
bool match(const VPSingleDefRecipe *R)
A helper to match an opcode against multiple recipe types.
match_combine_or(const LTy &Left, const RTy &Right)
Match a specified integer value or vector of all elements of that value.