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 return DefR;
144 else
145 return DefR && DefR->getOpcode() == Opcode;
146 }
147};
148
149template <unsigned Opcode, typename RecipeTy, typename... RecipeTys>
150struct MatchRecipeAndOpcode<Opcode, RecipeTy, RecipeTys...> {
151 static bool match(const VPRecipeBase *R) {
154 }
155};
156template <typename TupleTy, typename Fn, std::size_t... Is>
157bool CheckTupleElements(const TupleTy &Ops, Fn P, std::index_sequence<Is...>) {
158 return (P(std::get<Is>(Ops), Is) && ...);
159}
160
161/// Helper to check if predicate \p P holds on all tuple elements in \p Ops
162template <typename TupleTy, typename Fn>
163bool all_of_tuple_elements(const TupleTy &Ops, Fn P) {
164 return CheckTupleElements(
165 Ops, P, std::make_index_sequence<std::tuple_size<TupleTy>::value>{});
166}
167} // namespace detail
168
169template <typename Ops_t, unsigned Opcode, bool Commutative,
170 typename... RecipeTys>
172 Ops_t Ops;
173
175 static_assert(std::tuple_size<Ops_t>::value == 0 &&
176 "constructor can only be used with zero operands");
177 }
178 Recipe_match(Ops_t Ops) : Ops(Ops) {}
179 template <typename A_t, typename B_t>
180 Recipe_match(A_t A, B_t B) : Ops({A, B}) {
181 static_assert(std::tuple_size<Ops_t>::value == 2 &&
182 "constructor can only be used for binary matcher");
183 }
184
185 bool match(const VPValue *V) const {
186 auto *DefR = V->getDefiningRecipe();
187 return DefR && match(DefR);
188 }
189
190 bool match(const VPSingleDefRecipe *R) const {
191 return match(static_cast<const VPRecipeBase *>(R));
192 }
193
194 bool match(const VPRecipeBase *R) const {
196 return false;
197 assert(R->getNumOperands() == std::tuple_size<Ops_t>::value &&
198 "recipe with matched opcode the expected number of operands");
199
200 if (detail::all_of_tuple_elements(Ops, [R](auto Op, unsigned Idx) {
201 return Op.match(R->getOperand(Idx));
202 }))
203 return true;
204
205 return Commutative &&
206 detail::all_of_tuple_elements(Ops, [R](auto Op, unsigned Idx) {
207 return Op.match(R->getOperand(R->getNumOperands() - Idx - 1));
208 });
209 }
210};
211
212template <typename Op0_t, unsigned Opcode, typename... RecipeTys>
214 Recipe_match<std::tuple<Op0_t>, Opcode, false, RecipeTys...>;
215
216template <typename Op0_t, unsigned Opcode>
219
220template <typename Op0_t, unsigned Opcode>
224
225template <typename Op0_t, typename Op1_t, unsigned Opcode, bool Commutative,
226 typename... RecipeTys>
228 Recipe_match<std::tuple<Op0_t, Op1_t>, Opcode, Commutative, RecipeTys...>;
229
230template <typename Op0_t, typename Op1_t, unsigned Opcode>
232 BinaryRecipe_match<Op0_t, Op1_t, Opcode, /*Commutative*/ false,
234
235template <typename Op0_t, typename Op1_t, unsigned Opcode,
236 bool Commutative = false>
238 BinaryRecipe_match<Op0_t, Op1_t, Opcode, Commutative, VPWidenRecipe,
240
241template <unsigned Opcode, typename Op0_t>
243m_VPInstruction(const Op0_t &Op0) {
245}
246
247template <unsigned Opcode, typename Op0_t, typename Op1_t>
248inline BinaryVPInstruction_match<Op0_t, Op1_t, Opcode>
249m_VPInstruction(const Op0_t &Op0, const Op1_t &Op1) {
251}
252
253template <typename Op0_t>
254inline UnaryVPInstruction_match<Op0_t, VPInstruction::Not>
255m_Not(const Op0_t &Op0) {
256 return m_VPInstruction<VPInstruction::Not>(Op0);
257}
258
259template <typename Op0_t>
260inline UnaryVPInstruction_match<Op0_t, VPInstruction::BranchOnCond>
261m_BranchOnCond(const Op0_t &Op0) {
262 return m_VPInstruction<VPInstruction::BranchOnCond>(Op0);
263}
264
265template <typename Op0_t, typename Op1_t>
266inline BinaryVPInstruction_match<Op0_t, Op1_t, VPInstruction::ActiveLaneMask>
267m_ActiveLaneMask(const Op0_t &Op0, const Op1_t &Op1) {
268 return m_VPInstruction<VPInstruction::ActiveLaneMask>(Op0, Op1);
269}
270
271template <typename Op0_t, typename Op1_t>
272inline BinaryVPInstruction_match<Op0_t, Op1_t, VPInstruction::BranchOnCount>
273m_BranchOnCount(const Op0_t &Op0, const Op1_t &Op1) {
274 return m_VPInstruction<VPInstruction::BranchOnCount>(Op0, Op1);
275}
276
277template <unsigned Opcode, typename Op0_t>
280}
281
282template <typename Op0_t>
283inline AllUnaryRecipe_match<Op0_t, Instruction::Trunc>
284m_Trunc(const Op0_t &Op0) {
285 return m_Unary<Instruction::Trunc, Op0_t>(Op0);
286}
287
288template <typename Op0_t>
290 return m_Unary<Instruction::ZExt, Op0_t>(Op0);
291}
292
293template <typename Op0_t>
295 return m_Unary<Instruction::SExt, Op0_t>(Op0);
296}
297
298template <typename Op0_t>
300 AllUnaryRecipe_match<Op0_t, Instruction::SExt>>
301m_ZExtOrSExt(const Op0_t &Op0) {
302 return m_CombineOr(m_ZExt(Op0), m_SExt(Op0));
303}
304
305template <unsigned Opcode, typename Op0_t, typename Op1_t,
306 bool Commutative = false>
307inline AllBinaryRecipe_match<Op0_t, Op1_t, Opcode, Commutative>
308m_Binary(const Op0_t &Op0, const Op1_t &Op1) {
310}
311
312template <typename Op0_t, typename Op1_t>
313inline AllBinaryRecipe_match<Op0_t, Op1_t, Instruction::Mul>
314m_Mul(const Op0_t &Op0, const Op1_t &Op1) {
315 return m_Binary<Instruction::Mul, Op0_t, Op1_t>(Op0, Op1);
316}
317
318template <typename Op0_t, typename Op1_t>
319inline AllBinaryRecipe_match<Op0_t, Op1_t, Instruction::Mul,
320 /* Commutative =*/true>
321m_c_Mul(const Op0_t &Op0, const Op1_t &Op1) {
322 return m_Binary<Instruction::Mul, Op0_t, Op1_t, true>(Op0, Op1);
323}
324
325/// Match a binary OR operation. Note that while conceptually the operands can
326/// be matched commutatively, \p Commutative defaults to false in line with the
327/// IR-based pattern matching infrastructure. Use m_c_BinaryOr for a commutative
328/// version of the matcher.
329template <typename Op0_t, typename Op1_t, bool Commutative = false>
330inline AllBinaryRecipe_match<Op0_t, Op1_t, Instruction::Or, Commutative>
331m_BinaryOr(const Op0_t &Op0, const Op1_t &Op1) {
332 return m_Binary<Instruction::Or, Op0_t, Op1_t, Commutative>(Op0, Op1);
333}
334
335template <typename Op0_t, typename Op1_t>
336inline AllBinaryRecipe_match<Op0_t, Op1_t, Instruction::Or,
337 /*Commutative*/ true>
338m_c_BinaryOr(const Op0_t &Op0, const Op1_t &Op1) {
339 return m_BinaryOr<Op0_t, Op1_t, /*Commutative*/ true>(Op0, Op1);
340}
341
342template <typename Op0_t, typename Op1_t, typename Op2_t, unsigned Opcode>
346
347template <typename Op0_t, typename Op1_t, typename Op2_t>
349m_Select(const Op0_t &Op0, const Op1_t &Op1, const Op2_t &Op2) {
351 {Op0, Op1, Op2});
352}
353
354template <typename Op0_t, typename Op1_t>
355inline match_combine_or<
356 BinaryVPInstruction_match<Op0_t, Op1_t, VPInstruction::LogicalAnd>,
357 AllTernaryRecipe_match<Op0_t, Op1_t, specific_intval<1>,
358 Instruction::Select>>
359m_LogicalAnd(const Op0_t &Op0, const Op1_t &Op1) {
360 return m_CombineOr(
361 m_VPInstruction<VPInstruction::LogicalAnd, Op0_t, Op1_t>(Op0, Op1),
362 m_Select(Op0, Op1, m_False()));
363}
364
365template <typename Op0_t, typename Op1_t>
366inline AllTernaryRecipe_match<Op0_t, specific_intval<1>, Op1_t,
367 Instruction::Select>
368m_LogicalOr(const Op0_t &Op0, const Op1_t &Op1) {
369 return m_Select(Op0, m_True(), Op1);
370}
371
374
376 return VPCanonicalIVPHI_match();
377}
378
379template <typename Op0_t, typename Op1_t>
382
383template <typename Op0_t, typename Op1_t>
385 const Op1_t &Op1) {
387}
388
389template <typename Op0_t, typename Op1_t, typename Op2_t>
392
393template <typename Op0_t, typename Op1_t, typename Op2_t>
395m_DerivedIV(const Op0_t &Op0, const Op1_t &Op1, const Op2_t &Op2) {
396 return VPDerivedIV_match<Op0_t, Op1_t, Op2_t>({Op0, Op1, Op2});
397}
398
399} // namespace VPlanPatternMatch
400} // namespace llvm
401
402#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:3216
A recipe for converting the input value IV value to the corresponding value of an IV with different s...
Definition: VPlan.h:3393
This is a concrete Recipe that models a single VPlan-level instruction.
Definition: VPlan.h:1198
VPRecipeBase is a base class modeling a sequence of one or more output IR instructions.
Definition: VPlan.h:720
VPReplicateRecipe replicates a given instruction producing multiple scalar copies of the original sca...
Definition: VPlan.h:2760
A recipe for handling phi nodes of integer and floating-point inductions, producing their scalar valu...
Definition: VPlan.h:3462
VPSingleDef is a base class for recipes for modeling a sequence of one or more output IR that define ...
Definition: VPlan.h:847
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:1530
VPWidenRecipe is a recipe for producing a widened instruction using the opcode and operands of the re...
Definition: VPlan.h:1432
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)
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)
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:1817
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.