xref: /freebsd/contrib/llvm-project/llvm/include/llvm/Analysis/ScalarEvolutionPatternMatch.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
1 //===----------------------------------------------------------------------===//
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // This file provides a simple and efficient mechanism for performing general
9 // tree-based pattern matches on SCEVs, based on LLVM's IR pattern matchers.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef LLVM_ANALYSIS_SCALAREVOLUTIONPATTERNMATCH_H
14 #define LLVM_ANALYSIS_SCALAREVOLUTIONPATTERNMATCH_H
15 
16 #include "llvm/Analysis/ScalarEvolutionExpressions.h"
17 
18 namespace llvm {
19 namespace SCEVPatternMatch {
20 
match(const SCEV * S,const Pattern & P)21 template <typename Pattern> bool match(const SCEV *S, const Pattern &P) {
22   return P.match(S);
23 }
24 
25 template <typename Predicate> struct cst_pred_ty : public Predicate {
26   cst_pred_ty() = default;
cst_pred_tycst_pred_ty27   cst_pred_ty(uint64_t V) : Predicate(V) {}
matchcst_pred_ty28   bool match(const SCEV *S) const {
29     assert((isa<SCEVCouldNotCompute>(S) || !S->getType()->isVectorTy()) &&
30            "no vector types expected from SCEVs");
31     auto *C = dyn_cast<SCEVConstant>(S);
32     return C && this->isValue(C->getAPInt());
33   }
34 };
35 
36 struct is_zero {
isValueis_zero37   bool isValue(const APInt &C) const { return C.isZero(); }
38 };
39 
40 /// Match an integer 0.
m_scev_Zero()41 inline cst_pred_ty<is_zero> m_scev_Zero() { return cst_pred_ty<is_zero>(); }
42 
43 struct is_one {
isValueis_one44   bool isValue(const APInt &C) const { return C.isOne(); }
45 };
46 
47 /// Match an integer 1.
m_scev_One()48 inline cst_pred_ty<is_one> m_scev_One() { return cst_pred_ty<is_one>(); }
49 
50 struct is_all_ones {
isValueis_all_ones51   bool isValue(const APInt &C) const { return C.isAllOnes(); }
52 };
53 
54 /// Match an integer with all bits set.
m_scev_AllOnes()55 inline cst_pred_ty<is_all_ones> m_scev_AllOnes() {
56   return cst_pred_ty<is_all_ones>();
57 }
58 
59 template <typename Class> struct class_match {
matchclass_match60   template <typename ITy> bool match(ITy *V) const { return isa<Class>(V); }
61 };
62 
m_SCEV()63 inline class_match<const SCEV> m_SCEV() { return class_match<const SCEV>(); }
m_SCEVConstant()64 inline class_match<const SCEVConstant> m_SCEVConstant() {
65   return class_match<const SCEVConstant>();
66 }
m_SCEVVScale()67 inline class_match<const SCEVVScale> m_SCEVVScale() {
68   return class_match<const SCEVVScale>();
69 }
70 
71 template <typename Class> struct bind_ty {
72   Class *&VR;
73 
bind_tybind_ty74   bind_ty(Class *&V) : VR(V) {}
75 
matchbind_ty76   template <typename ITy> bool match(ITy *V) const {
77     if (auto *CV = dyn_cast<Class>(V)) {
78       VR = CV;
79       return true;
80     }
81     return false;
82   }
83 };
84 
85 /// Match a SCEV, capturing it if we match.
m_SCEV(const SCEV * & V)86 inline bind_ty<const SCEV> m_SCEV(const SCEV *&V) { return V; }
m_SCEVConstant(const SCEVConstant * & V)87 inline bind_ty<const SCEVConstant> m_SCEVConstant(const SCEVConstant *&V) {
88   return V;
89 }
m_SCEVUnknown(const SCEVUnknown * & V)90 inline bind_ty<const SCEVUnknown> m_SCEVUnknown(const SCEVUnknown *&V) {
91   return V;
92 }
93 
94 /// Match a specified const SCEV *.
95 struct specificscev_ty {
96   const SCEV *Expr;
97 
specificscev_tyspecificscev_ty98   specificscev_ty(const SCEV *Expr) : Expr(Expr) {}
99 
matchspecificscev_ty100   template <typename ITy> bool match(ITy *S) const { return S == Expr; }
101 };
102 
103 /// Match if we have a specific specified SCEV.
m_scev_Specific(const SCEV * S)104 inline specificscev_ty m_scev_Specific(const SCEV *S) { return S; }
105 
106 struct is_specific_cst {
107   uint64_t CV;
is_specific_cstis_specific_cst108   is_specific_cst(uint64_t C) : CV(C) {}
isValueis_specific_cst109   bool isValue(const APInt &C) const { return C == CV; }
110 };
111 
112 /// Match an SCEV constant with a plain unsigned integer.
m_scev_SpecificInt(uint64_t V)113 inline cst_pred_ty<is_specific_cst> m_scev_SpecificInt(uint64_t V) { return V; }
114 
115 struct bind_cst_ty {
116   const APInt *&CR;
117 
bind_cst_tybind_cst_ty118   bind_cst_ty(const APInt *&Op0) : CR(Op0) {}
119 
matchbind_cst_ty120   bool match(const SCEV *S) const {
121     assert((isa<SCEVCouldNotCompute>(S) || !S->getType()->isVectorTy()) &&
122            "no vector types expected from SCEVs");
123     auto *C = dyn_cast<SCEVConstant>(S);
124     if (!C)
125       return false;
126     CR = &C->getAPInt();
127     return true;
128   }
129 };
130 
131 /// Match an SCEV constant and bind it to an APInt.
m_scev_APInt(const APInt * & C)132 inline bind_cst_ty m_scev_APInt(const APInt *&C) { return C; }
133 
134 /// Match a unary SCEV.
135 template <typename SCEVTy, typename Op0_t> struct SCEVUnaryExpr_match {
136   Op0_t Op0;
137 
SCEVUnaryExpr_matchSCEVUnaryExpr_match138   SCEVUnaryExpr_match(Op0_t Op0) : Op0(Op0) {}
139 
matchSCEVUnaryExpr_match140   bool match(const SCEV *S) const {
141     auto *E = dyn_cast<SCEVTy>(S);
142     return E && E->getNumOperands() == 1 && Op0.match(E->getOperand(0));
143   }
144 };
145 
146 template <typename SCEVTy, typename Op0_t>
m_scev_Unary(const Op0_t & Op0)147 inline SCEVUnaryExpr_match<SCEVTy, Op0_t> m_scev_Unary(const Op0_t &Op0) {
148   return SCEVUnaryExpr_match<SCEVTy, Op0_t>(Op0);
149 }
150 
151 template <typename Op0_t>
152 inline SCEVUnaryExpr_match<SCEVSignExtendExpr, Op0_t>
m_scev_SExt(const Op0_t & Op0)153 m_scev_SExt(const Op0_t &Op0) {
154   return m_scev_Unary<SCEVSignExtendExpr>(Op0);
155 }
156 
157 template <typename Op0_t>
158 inline SCEVUnaryExpr_match<SCEVZeroExtendExpr, Op0_t>
m_scev_ZExt(const Op0_t & Op0)159 m_scev_ZExt(const Op0_t &Op0) {
160   return m_scev_Unary<SCEVZeroExtendExpr>(Op0);
161 }
162 
163 /// Match a binary SCEV.
164 template <typename SCEVTy, typename Op0_t, typename Op1_t>
165 struct SCEVBinaryExpr_match {
166   Op0_t Op0;
167   Op1_t Op1;
168 
SCEVBinaryExpr_matchSCEVBinaryExpr_match169   SCEVBinaryExpr_match(Op0_t Op0, Op1_t Op1) : Op0(Op0), Op1(Op1) {}
170 
matchSCEVBinaryExpr_match171   bool match(const SCEV *S) const {
172     auto *E = dyn_cast<SCEVTy>(S);
173     return E && E->getNumOperands() == 2 && Op0.match(E->getOperand(0)) &&
174            Op1.match(E->getOperand(1));
175   }
176 };
177 
178 template <typename SCEVTy, typename Op0_t, typename Op1_t>
179 inline SCEVBinaryExpr_match<SCEVTy, Op0_t, Op1_t>
m_scev_Binary(const Op0_t & Op0,const Op1_t & Op1)180 m_scev_Binary(const Op0_t &Op0, const Op1_t &Op1) {
181   return SCEVBinaryExpr_match<SCEVTy, Op0_t, Op1_t>(Op0, Op1);
182 }
183 
184 template <typename Op0_t, typename Op1_t>
185 inline SCEVBinaryExpr_match<SCEVAddExpr, Op0_t, Op1_t>
m_scev_Add(const Op0_t & Op0,const Op1_t & Op1)186 m_scev_Add(const Op0_t &Op0, const Op1_t &Op1) {
187   return m_scev_Binary<SCEVAddExpr>(Op0, Op1);
188 }
189 
190 template <typename Op0_t, typename Op1_t>
191 inline SCEVBinaryExpr_match<SCEVMulExpr, Op0_t, Op1_t>
m_scev_Mul(const Op0_t & Op0,const Op1_t & Op1)192 m_scev_Mul(const Op0_t &Op0, const Op1_t &Op1) {
193   return m_scev_Binary<SCEVMulExpr>(Op0, Op1);
194 }
195 
196 template <typename Op0_t, typename Op1_t>
197 inline SCEVBinaryExpr_match<SCEVUDivExpr, Op0_t, Op1_t>
m_scev_UDiv(const Op0_t & Op0,const Op1_t & Op1)198 m_scev_UDiv(const Op0_t &Op0, const Op1_t &Op1) {
199   return m_scev_Binary<SCEVUDivExpr>(Op0, Op1);
200 }
201 
m_Loop()202 inline class_match<const Loop> m_Loop() { return class_match<const Loop>(); }
203 
204 /// Match an affine SCEVAddRecExpr.
205 template <typename Op0_t, typename Op1_t, typename Loop_t>
206 struct SCEVAffineAddRec_match {
207   SCEVBinaryExpr_match<SCEVAddRecExpr, Op0_t, Op1_t> Ops;
208   Loop_t Loop;
209 
SCEVAffineAddRec_matchSCEVAffineAddRec_match210   SCEVAffineAddRec_match(Op0_t Op0, Op1_t Op1, Loop_t Loop)
211       : Ops(Op0, Op1), Loop(Loop) {}
212 
matchSCEVAffineAddRec_match213   bool match(const SCEV *S) const {
214     return Ops.match(S) && Loop.match(cast<SCEVAddRecExpr>(S)->getLoop());
215   }
216 };
217 
218 /// Match a specified const Loop*.
219 struct specificloop_ty {
220   const Loop *L;
221 
specificloop_tyspecificloop_ty222   specificloop_ty(const Loop *L) : L(L) {}
223 
matchspecificloop_ty224   bool match(const Loop *L) const { return L == this->L; }
225 };
226 
m_SpecificLoop(const Loop * L)227 inline specificloop_ty m_SpecificLoop(const Loop *L) { return L; }
228 
m_Loop(const Loop * & L)229 inline bind_ty<const Loop> m_Loop(const Loop *&L) { return L; }
230 
231 template <typename Op0_t, typename Op1_t>
232 inline SCEVAffineAddRec_match<Op0_t, Op1_t, class_match<const Loop>>
m_scev_AffineAddRec(const Op0_t & Op0,const Op1_t & Op1)233 m_scev_AffineAddRec(const Op0_t &Op0, const Op1_t &Op1) {
234   return SCEVAffineAddRec_match<Op0_t, Op1_t, class_match<const Loop>>(
235       Op0, Op1, m_Loop());
236 }
237 
238 template <typename Op0_t, typename Op1_t, typename Loop_t>
239 inline SCEVAffineAddRec_match<Op0_t, Op1_t, Loop_t>
m_scev_AffineAddRec(const Op0_t & Op0,const Op1_t & Op1,const Loop_t & L)240 m_scev_AffineAddRec(const Op0_t &Op0, const Op1_t &Op1, const Loop_t &L) {
241   return SCEVAffineAddRec_match<Op0_t, Op1_t, Loop_t>(Op0, Op1, L);
242 }
243 
244 } // namespace SCEVPatternMatch
245 } // namespace llvm
246 
247 #endif
248