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 P.match(V);
30}
31
32template <typename Pattern> bool match(VPUser *U, const Pattern &P) {
33 auto *R = dyn_cast<VPRecipeBase>(U);
34 return R && match(R, P);
35}
36
37template <typename Class> struct class_match {
38 template <typename ITy> bool match(ITy *V) const { return isa<Class>(V); }
39};
40
41/// Match an arbitrary VPValue and ignore it.
43
44template <typename Class> struct bind_ty {
45 Class *&VR;
46
47 bind_ty(Class *&V) : VR(V) {}
48
49 template <typename ITy> bool match(ITy *V) const {
50 if (auto *CV = dyn_cast<Class>(V)) {
51 VR = CV;
52 return true;
53 }
54 return false;
55 }
56};
57
58/// Match a specified VPValue.
60 const VPValue *Val;
61
62 specificval_ty(const VPValue *V) : Val(V) {}
63
64 bool match(VPValue *VPV) const { return VPV == Val; }
65};
66
67inline specificval_ty m_Specific(const VPValue *VPV) { return VPV; }
68
69/// Match a specified integer value or vector of all elements of that
70/// value. \p BitWidth optionally specifies the bitwidth the matched constant
71/// must have. If it is 0, the matched constant can have any bitwidth.
72template <unsigned BitWidth = 0> struct specific_intval {
74
76
77 bool match(VPValue *VPV) const {
78 if (!VPV->isLiveIn())
79 return false;
80 Value *V = VPV->getLiveInIRValue();
81 if (!V)
82 return false;
83 const auto *CI = dyn_cast<ConstantInt>(V);
84 if (!CI && V->getType()->isVectorTy())
85 if (const auto *C = dyn_cast<Constant>(V))
86 CI = dyn_cast_or_null<ConstantInt>(
87 C->getSplatValue(/*AllowPoison=*/false));
88 if (!CI)
89 return false;
90
91 if (BitWidth != 0 && CI->getBitWidth() != BitWidth)
92 return false;
93 return APInt::isSameValue(CI->getValue(), Val);
94 }
95};
96
98 return specific_intval<0>(APInt(64, V));
99}
100
102
104
105/// Matching combinators
106template <typename LTy, typename RTy> struct match_combine_or {
107 LTy L;
108 RTy R;
109
110 match_combine_or(const LTy &Left, const RTy &Right) : L(Left), R(Right) {}
111
112 template <typename ITy> bool match(ITy *V) const {
113 if (L.match(V))
114 return true;
115 if (R.match(V))
116 return true;
117 return false;
118 }
119};
120
121template <typename LTy, typename RTy>
122inline match_combine_or<LTy, RTy> m_CombineOr(const LTy &L, const RTy &R) {
123 return match_combine_or<LTy, RTy>(L, R);
124}
125
126/// Match a VPValue, capturing it if we match.
127inline bind_ty<VPValue> m_VPValue(VPValue *&V) { return V; }
128
129namespace detail {
130
131/// A helper to match an opcode against multiple recipe types.
132template <unsigned Opcode, typename...> struct MatchRecipeAndOpcode {};
133
134template <unsigned Opcode, typename RecipeTy>
136 static bool match(const VPRecipeBase *R) {
137 auto *DefR = dyn_cast<RecipeTy>(R);
138 // Check for recipes that do not have opcodes.
139 if constexpr (std::is_same<RecipeTy, VPScalarIVStepsRecipe>::value ||
140 std::is_same<RecipeTy, VPCanonicalIVPHIRecipe>::value ||
141 std::is_same<RecipeTy, VPWidenSelectRecipe>::value ||
142 std::is_same<RecipeTy, VPDerivedIVRecipe>::value ||
143 std::is_same<RecipeTy, VPWidenGEPRecipe>::value)
144 return DefR;
145 else
146 return DefR && DefR->getOpcode() == Opcode;
147 }
148};
149
150template <unsigned Opcode, typename RecipeTy, typename... RecipeTys>
151struct MatchRecipeAndOpcode<Opcode, RecipeTy, RecipeTys...> {
152 static bool match(const VPRecipeBase *R) {
155 }
156};
157template <typename TupleTy, typename Fn, std::size_t... Is>
158bool CheckTupleElements(const TupleTy &Ops, Fn P, std::index_sequence<Is...>) {
159 return (P(std::get<Is>(Ops), Is) && ...);
160}
161
162/// Helper to check if predicate \p P holds on all tuple elements in \p Ops
163template <typename TupleTy, typename Fn>
164bool all_of_tuple_elements(const TupleTy &Ops, Fn P) {
165 return CheckTupleElements(
166 Ops, P, std::make_index_sequence<std::tuple_size<TupleTy>::value>{});
167}
168} // namespace detail
169
170template <typename Ops_t, unsigned Opcode, bool Commutative,
171 typename... RecipeTys>
173 Ops_t Ops;
174
176 static_assert(std::tuple_size<Ops_t>::value == 0 &&
177 "constructor can only be used with zero operands");
178 }
179 Recipe_match(Ops_t Ops) : Ops(Ops) {}
180 template <typename A_t, typename B_t>
181 Recipe_match(A_t A, B_t B) : Ops({A, B}) {
182 static_assert(std::tuple_size<Ops_t>::value == 2 &&
183 "constructor can only be used for binary matcher");
184 }
185
186 bool match(const VPValue *V) const {
187 auto *DefR = V->getDefiningRecipe();
188 return DefR && match(DefR);
189 }
190
191 bool match(const VPSingleDefRecipe *R) const {
192 return match(static_cast<const VPRecipeBase *>(R));
193 }
194
195 bool match(const VPRecipeBase *R) const {
197 return false;
198 assert(R->getNumOperands() == std::tuple_size<Ops_t>::value &&
199 "recipe with matched opcode the expected number of operands");
200
201 if (detail::all_of_tuple_elements(Ops, [R](auto Op, unsigned Idx) {
202 return Op.match(R->getOperand(Idx));
203 }))
204 return true;
205
206 return Commutative &&
207 detail::all_of_tuple_elements(Ops, [R](auto Op, unsigned Idx) {
208 return Op.match(R->getOperand(R->getNumOperands() - Idx - 1));
209 });
210 }
211};
212
213template <typename Op0_t, unsigned Opcode, typename... RecipeTys>
215 Recipe_match<std::tuple<Op0_t>, Opcode, false, RecipeTys...>;
216
217template <typename Op0_t, unsigned Opcode>
220
221template <typename Op0_t, unsigned Opcode>
225
226template <typename Op0_t, typename Op1_t, unsigned Opcode, bool Commutative,
227 typename... RecipeTys>
229 Recipe_match<std::tuple<Op0_t, Op1_t>, Opcode, Commutative, RecipeTys...>;
230
231template <typename Op0_t, typename Op1_t, unsigned Opcode>
233 BinaryRecipe_match<Op0_t, Op1_t, Opcode, /*Commutative*/ false,
235
236template <typename Op0_t, typename Op1_t, unsigned Opcode,
237 bool Commutative = false>
239 BinaryRecipe_match<Op0_t, Op1_t, Opcode, Commutative, VPWidenRecipe,
241
242template <unsigned Opcode, typename Op0_t>
244m_VPInstruction(const Op0_t &Op0) {
246}
247
248template <unsigned Opcode, typename Op0_t, typename Op1_t>
249inline BinaryVPInstruction_match<Op0_t, Op1_t, Opcode>
250m_VPInstruction(const Op0_t &Op0, const Op1_t &Op1) {
252}
253
254template <typename Op0_t>
255inline UnaryVPInstruction_match<Op0_t, VPInstruction::Not>
256m_Not(const Op0_t &Op0) {
257 return m_VPInstruction<VPInstruction::Not>(Op0);
258}
259
260template <typename Op0_t>
261inline UnaryVPInstruction_match<Op0_t, VPInstruction::BranchOnCond>
262m_BranchOnCond(const Op0_t &Op0) {
263 return m_VPInstruction<VPInstruction::BranchOnCond>(Op0);
264}
265
266template <typename Op0_t, typename Op1_t>
267inline BinaryVPInstruction_match<Op0_t, Op1_t, VPInstruction::ActiveLaneMask>
268m_ActiveLaneMask(const Op0_t &Op0, const Op1_t &Op1) {
269 return m_VPInstruction<VPInstruction::ActiveLaneMask>(Op0, Op1);
270}
271
272template <typename Op0_t, typename Op1_t>
273inline BinaryVPInstruction_match<Op0_t, Op1_t, VPInstruction::BranchOnCount>
274m_BranchOnCount(const Op0_t &Op0, const Op1_t &Op1) {
275 return m_VPInstruction<VPInstruction::BranchOnCount>(Op0, Op1);
276}
277
278template <unsigned Opcode, typename Op0_t>
281}
282
283template <typename Op0_t>
284inline AllUnaryRecipe_match<Op0_t, Instruction::Trunc>
285m_Trunc(const Op0_t &Op0) {
286 return m_Unary<Instruction::Trunc, Op0_t>(Op0);
287}
288
289template <typename Op0_t>
291 return m_Unary<Instruction::ZExt, Op0_t>(Op0);
292}
293
294template <typename Op0_t>
296 return m_Unary<Instruction::SExt, Op0_t>(Op0);
297}
298
299template <typename Op0_t>
301 AllUnaryRecipe_match<Op0_t, Instruction::SExt>>
302m_ZExtOrSExt(const Op0_t &Op0) {
303 return m_CombineOr(m_ZExt(Op0), m_SExt(Op0));
304}
305
306template <unsigned Opcode, typename Op0_t, typename Op1_t,
307 bool Commutative = false>
308inline AllBinaryRecipe_match<Op0_t, Op1_t, Opcode, Commutative>
309m_Binary(const Op0_t &Op0, const Op1_t &Op1) {
311}
312
313template <unsigned Opcode, typename Op0_t, typename Op1_t>
314inline AllBinaryRecipe_match<Op0_t, Op1_t, Opcode, true>
315m_c_Binary(const Op0_t &Op0, const Op1_t &Op1) {
317}
318
319template <typename Op0_t, typename Op1_t>
320inline AllBinaryRecipe_match<Op0_t, Op1_t, Instruction::Mul>
321m_Mul(const Op0_t &Op0, const Op1_t &Op1) {
322 return m_Binary<Instruction::Mul, Op0_t, Op1_t>(Op0, Op1);
323}
324
325template <typename Op0_t, typename Op1_t>
326inline AllBinaryRecipe_match<Op0_t, Op1_t, Instruction::Mul,
327 /* Commutative =*/true>
328m_c_Mul(const Op0_t &Op0, const Op1_t &Op1) {
329 return m_Binary<Instruction::Mul, Op0_t, Op1_t, true>(Op0, Op1);
330}
331
332/// Match a binary OR operation. Note that while conceptually the operands can
333/// be matched commutatively, \p Commutative defaults to false in line with the
334/// IR-based pattern matching infrastructure. Use m_c_BinaryOr for a commutative
335/// version of the matcher.
336template <typename Op0_t, typename Op1_t, bool Commutative = false>
337inline AllBinaryRecipe_match<Op0_t, Op1_t, Instruction::Or, Commutative>
338m_BinaryOr(const Op0_t &Op0, const Op1_t &Op1) {
339 return m_Binary<Instruction::Or, Op0_t, Op1_t, Commutative>(Op0, Op1);
340}
341
342template <typename Op0_t, typename Op1_t>
343inline AllBinaryRecipe_match<Op0_t, Op1_t, Instruction::Or,
344 /*Commutative*/ true>
345m_c_BinaryOr(const Op0_t &Op0, const Op1_t &Op1) {
346 return m_BinaryOr<Op0_t, Op1_t, /*Commutative*/ true>(Op0, Op1);
347}
348
349template <typename Op0_t, typename Op1_t>
351 BinaryRecipe_match<Op0_t, Op1_t, Instruction::GetElementPtr, false,
354
355template <typename Op0_t, typename Op1_t>
357 const Op1_t &Op1) {
358 return GEPLikeRecipe_match<Op0_t, Op1_t>(Op0, Op1);
359}
360
361template <typename Op0_t, typename Op1_t, typename Op2_t, unsigned Opcode>
365
366template <typename Op0_t, typename Op1_t, typename Op2_t>
368m_Select(const Op0_t &Op0, const Op1_t &Op1, const Op2_t &Op2) {
370 {Op0, Op1, Op2});
371}
372
373template <typename Op0_t, typename Op1_t>
374inline match_combine_or<
375 BinaryVPInstruction_match<Op0_t, Op1_t, VPInstruction::LogicalAnd>,
376 AllTernaryRecipe_match<Op0_t, Op1_t, specific_intval<1>,
377 Instruction::Select>>
378m_LogicalAnd(const Op0_t &Op0, const Op1_t &Op1) {
379 return m_CombineOr(
380 m_VPInstruction<VPInstruction::LogicalAnd, Op0_t, Op1_t>(Op0, Op1),
381 m_Select(Op0, Op1, m_False()));
382}
383
384template <typename Op0_t, typename Op1_t>
385inline AllTernaryRecipe_match<Op0_t, specific_intval<1>, Op1_t,
386 Instruction::Select>
387m_LogicalOr(const Op0_t &Op0, const Op1_t &Op1) {
388 return m_Select(Op0, m_True(), Op1);
389}
390
393
395 return VPCanonicalIVPHI_match();
396}
397
398template <typename Op0_t, typename Op1_t>
401
402template <typename Op0_t, typename Op1_t>
404 const Op1_t &Op1) {
406}
407
408template <typename Op0_t, typename Op1_t, typename Op2_t>
411
412template <typename Op0_t, typename Op1_t, typename Op2_t>
414m_DerivedIV(const Op0_t &Op0, const Op1_t &Op1, const Op2_t &Op2) {
415 return VPDerivedIV_match<Op0_t, Op1_t, Op2_t>({Op0, Op1, Op2});
416}
417
418} // namespace VPlanPatternMatch
419} // namespace llvm
420
421#endif
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
#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:553
This class represents an Operation in the Expression.
Canonical scalar induction phi of the vector loop.
Definition: VPlan.h:3172
A recipe for converting the input value IV value to the corresponding value of an IV with different s...
Definition: VPlan.h:3349
This is a concrete Recipe that models a single VPlan-level instruction.
Definition: VPlan.h:1191
VPRecipeBase is a base class modeling a sequence of one or more output IR instructions.
Definition: VPlan.h:714
VPReplicateRecipe replicates a given instruction producing multiple scalar copies of the original sca...
Definition: VPlan.h:2716
A recipe for handling phi nodes of integer and floating-point inductions, producing their scalar valu...
Definition: VPlan.h:3418
VPSingleDef is a base class for recipes for modeling a sequence of one or more output IR that define ...
Definition: VPlan.h:841
This class augments VPValue with operands which provide the inverse def-use edges from VPValue's user...
Definition: VPlanValue.h:200
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:1523
A recipe for handling GEP instructions.
Definition: VPlan.h:1850
VPWidenRecipe is a recipe for producing a widened instruction using the opcode and operands of the re...
Definition: VPlan.h:1425
LLVM Value Representation.
Definition: Value.h:74
@ C
The default llvm calling convention, compatible with C.
Definition: CallingConv.h:34
auto m_LogicalOr()
Matches L || R where L and R are arbitrary values.
auto m_LogicalAnd()
Matches L && R where L and R are arbitrary values.
bool CheckTupleElements(const TupleTy &Ops, Fn P, std::index_sequence< Is... >)
bool all_of_tuple_elements(const TupleTy &Ops, Fn P)
Helper to check if predicate P holds on all tuple elements in Ops.
AllBinaryRecipe_match< Op0_t, Op1_t, Instruction::Or, Commutative > m_BinaryOr(const Op0_t &Op0, const Op1_t &Op1)
Match a binary OR operation.
AllTernaryRecipe_match< Op0_t, Op1_t, Op2_t, Instruction::Select > m_Select(const Op0_t &Op0, const Op1_t &Op1, const Op2_t &Op2)
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)
GEPLikeRecipe_match< Op0_t, Op1_t > m_GetElementPtr(const Op0_t &Op0, const Op1_t &Op1)
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)
specificval_ty m_Specific(const VPValue *VPV)
specific_intval< 1 > m_False()
VPDerivedIV_match< Op0_t, Op1_t, Op2_t > m_DerivedIV(const Op0_t &Op0, const Op1_t &Op1, const Op2_t &Op2)
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)
specific_intval< 1 > m_True()
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)
AllBinaryRecipe_match< Op0_t, Op1_t, Opcode, true > m_c_Binary(const Op0_t &Op0, const Op1_t &Op1)
Recipe_match< std::tuple<>, 0, false, VPCanonicalIVPHIRecipe > VPCanonicalIVPHI_match
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:217
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:1873
Implement std::hash so that hash_code can be used in STL containers.
Definition: BitVector.h:858
A recipe for widening select instructions.
Definition: VPlan.h:1812
bool match(const VPSingleDefRecipe *R) const
bool match(const VPValue *V) const
bool match(const VPRecipeBase *R) const
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.