blob: 797f5e542fb6cd78d400696f60b66400fefaaef7 [file] [log] [blame]
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01001//== ----- llvm/CodeGen/GlobalISel/MIPatternMatch.h --------------------- == //
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10/// Contains matchers for matching SSA Machine Instructions.
11//
12//===----------------------------------------------------------------------===//
13#ifndef LLVM_GMIR_PATTERNMATCH_H
14#define LLVM_GMIR_PATTERNMATCH_H
15
16#include "llvm/ADT/APFloat.h"
17#include "llvm/ADT/APInt.h"
18#include "llvm/CodeGen/GlobalISel/Utils.h"
19#include "llvm/CodeGen/MachineRegisterInfo.h"
20
21namespace llvm {
22namespace MIPatternMatch {
23
24template <typename Reg, typename Pattern>
25bool mi_match(Reg R, MachineRegisterInfo &MRI, Pattern &&P) {
26 return P.match(MRI, R);
27}
28
29// TODO: Extend for N use.
30template <typename SubPatternT> struct OneUse_match {
31 SubPatternT SubPat;
32 OneUse_match(const SubPatternT &SP) : SubPat(SP) {}
33
34 template <typename OpTy>
35 bool match(const MachineRegisterInfo &MRI, unsigned Reg) {
36 return MRI.hasOneUse(Reg) && SubPat.match(MRI, Reg);
37 }
38};
39
40template <typename SubPat>
41inline OneUse_match<SubPat> m_OneUse(const SubPat &SP) {
42 return SP;
43}
44
45struct ConstantMatch {
46 int64_t &CR;
47 ConstantMatch(int64_t &C) : CR(C) {}
48 bool match(const MachineRegisterInfo &MRI, unsigned Reg) {
49 if (auto MaybeCst = getConstantVRegVal(Reg, MRI)) {
50 CR = *MaybeCst;
51 return true;
52 }
53 return false;
54 }
55};
56
57inline ConstantMatch m_ICst(int64_t &Cst) { return ConstantMatch(Cst); }
58
59// TODO: Rework this for different kinds of MachineOperand.
60// Currently assumes the Src for a match is a register.
61// We might want to support taking in some MachineOperands and call getReg on
62// that.
63
64struct operand_type_match {
65 bool match(const MachineRegisterInfo &MRI, unsigned Reg) { return true; }
66 bool match(const MachineRegisterInfo &MRI, MachineOperand *MO) {
67 return MO->isReg();
68 }
69};
70
71inline operand_type_match m_Reg() { return operand_type_match(); }
72
73/// Matching combinators.
74template <typename... Preds> struct And {
75 template <typename MatchSrc>
76 bool match(MachineRegisterInfo &MRI, MatchSrc &&src) {
77 return true;
78 }
79};
80
81template <typename Pred, typename... Preds>
82struct And<Pred, Preds...> : And<Preds...> {
83 Pred P;
84 And(Pred &&p, Preds &&... preds)
85 : And<Preds...>(std::forward<Preds>(preds)...), P(std::forward<Pred>(p)) {
86 }
87 template <typename MatchSrc>
88 bool match(MachineRegisterInfo &MRI, MatchSrc &&src) {
89 return P.match(MRI, src) && And<Preds...>::match(MRI, src);
90 }
91};
92
93template <typename... Preds> struct Or {
94 template <typename MatchSrc>
95 bool match(MachineRegisterInfo &MRI, MatchSrc &&src) {
96 return false;
97 }
98};
99
100template <typename Pred, typename... Preds>
101struct Or<Pred, Preds...> : Or<Preds...> {
102 Pred P;
103 Or(Pred &&p, Preds &&... preds)
104 : Or<Preds...>(std::forward<Preds>(preds)...), P(std::forward<Pred>(p)) {}
105 template <typename MatchSrc>
106 bool match(MachineRegisterInfo &MRI, MatchSrc &&src) {
107 return P.match(MRI, src) || Or<Preds...>::match(MRI, src);
108 }
109};
110
111template <typename... Preds> And<Preds...> m_all_of(Preds &&... preds) {
112 return And<Preds...>(std::forward<Preds>(preds)...);
113}
114
115template <typename... Preds> Or<Preds...> m_any_of(Preds &&... preds) {
116 return Or<Preds...>(std::forward<Preds>(preds)...);
117}
118
119template <typename BindTy> struct bind_helper {
120 static bool bind(const MachineRegisterInfo &MRI, BindTy &VR, BindTy &V) {
121 VR = V;
122 return true;
123 }
124};
125
126template <> struct bind_helper<MachineInstr *> {
127 static bool bind(const MachineRegisterInfo &MRI, MachineInstr *&MI,
128 unsigned Reg) {
129 MI = MRI.getVRegDef(Reg);
130 if (MI)
131 return true;
132 return false;
133 }
134};
135
136template <> struct bind_helper<LLT> {
137 static bool bind(const MachineRegisterInfo &MRI, LLT &Ty, unsigned Reg) {
138 Ty = MRI.getType(Reg);
139 if (Ty.isValid())
140 return true;
141 return false;
142 }
143};
144
145template <> struct bind_helper<const ConstantFP *> {
146 static bool bind(const MachineRegisterInfo &MRI, const ConstantFP *&F,
147 unsigned Reg) {
148 F = getConstantFPVRegVal(Reg, MRI);
149 if (F)
150 return true;
151 return false;
152 }
153};
154
155template <typename Class> struct bind_ty {
156 Class &VR;
157
158 bind_ty(Class &V) : VR(V) {}
159
160 template <typename ITy> bool match(const MachineRegisterInfo &MRI, ITy &&V) {
161 return bind_helper<Class>::bind(MRI, VR, V);
162 }
163};
164
165inline bind_ty<unsigned> m_Reg(unsigned &R) { return R; }
166inline bind_ty<MachineInstr *> m_MInstr(MachineInstr *&MI) { return MI; }
167inline bind_ty<LLT> m_Type(LLT &Ty) { return Ty; }
168
169// Helper for matching G_FCONSTANT
170inline bind_ty<const ConstantFP *> m_GFCst(const ConstantFP *&C) { return C; }
171
172// General helper for all the binary generic MI such as G_ADD/G_SUB etc
173template <typename LHS_P, typename RHS_P, unsigned Opcode,
174 bool Commutable = false>
175struct BinaryOp_match {
176 LHS_P L;
177 RHS_P R;
178
179 BinaryOp_match(const LHS_P &LHS, const RHS_P &RHS) : L(LHS), R(RHS) {}
180 template <typename OpTy> bool match(MachineRegisterInfo &MRI, OpTy &&Op) {
181 MachineInstr *TmpMI;
182 if (mi_match(Op, MRI, m_MInstr(TmpMI))) {
183 if (TmpMI->getOpcode() == Opcode && TmpMI->getNumOperands() == 3) {
184 return (L.match(MRI, TmpMI->getOperand(1).getReg()) &&
185 R.match(MRI, TmpMI->getOperand(2).getReg())) ||
186 (Commutable && (R.match(MRI, TmpMI->getOperand(1).getReg()) &&
187 L.match(MRI, TmpMI->getOperand(2).getReg())));
188 }
189 }
190 return false;
191 }
192};
193
194template <typename LHS, typename RHS>
195inline BinaryOp_match<LHS, RHS, TargetOpcode::G_ADD, true>
196m_GAdd(const LHS &L, const RHS &R) {
197 return BinaryOp_match<LHS, RHS, TargetOpcode::G_ADD, true>(L, R);
198}
199
200template <typename LHS, typename RHS>
201inline BinaryOp_match<LHS, RHS, TargetOpcode::G_SUB> m_GSub(const LHS &L,
202 const RHS &R) {
203 return BinaryOp_match<LHS, RHS, TargetOpcode::G_SUB>(L, R);
204}
205
206template <typename LHS, typename RHS>
207inline BinaryOp_match<LHS, RHS, TargetOpcode::G_MUL, true>
208m_GMul(const LHS &L, const RHS &R) {
209 return BinaryOp_match<LHS, RHS, TargetOpcode::G_MUL, true>(L, R);
210}
211
212template <typename LHS, typename RHS>
213inline BinaryOp_match<LHS, RHS, TargetOpcode::G_FADD, true>
214m_GFAdd(const LHS &L, const RHS &R) {
215 return BinaryOp_match<LHS, RHS, TargetOpcode::G_FADD, true>(L, R);
216}
217
218template <typename LHS, typename RHS>
219inline BinaryOp_match<LHS, RHS, TargetOpcode::G_FMUL, true>
220m_GFMul(const LHS &L, const RHS &R) {
221 return BinaryOp_match<LHS, RHS, TargetOpcode::G_FMUL, true>(L, R);
222}
223
224template <typename LHS, typename RHS>
225inline BinaryOp_match<LHS, RHS, TargetOpcode::G_AND, true>
226m_GAnd(const LHS &L, const RHS &R) {
227 return BinaryOp_match<LHS, RHS, TargetOpcode::G_AND, true>(L, R);
228}
229
230template <typename LHS, typename RHS>
231inline BinaryOp_match<LHS, RHS, TargetOpcode::G_OR, true> m_GOr(const LHS &L,
232 const RHS &R) {
233 return BinaryOp_match<LHS, RHS, TargetOpcode::G_OR, true>(L, R);
234}
235
236// Helper for unary instructions (G_[ZSA]EXT/G_TRUNC) etc
237template <typename SrcTy, unsigned Opcode> struct UnaryOp_match {
238 SrcTy L;
239
240 UnaryOp_match(const SrcTy &LHS) : L(LHS) {}
241 template <typename OpTy> bool match(MachineRegisterInfo &MRI, OpTy &&Op) {
242 MachineInstr *TmpMI;
243 if (mi_match(Op, MRI, m_MInstr(TmpMI))) {
244 if (TmpMI->getOpcode() == Opcode && TmpMI->getNumOperands() == 2) {
245 return L.match(MRI, TmpMI->getOperand(1).getReg());
246 }
247 }
248 return false;
249 }
250};
251
252template <typename SrcTy>
253inline UnaryOp_match<SrcTy, TargetOpcode::G_ANYEXT>
254m_GAnyExt(const SrcTy &Src) {
255 return UnaryOp_match<SrcTy, TargetOpcode::G_ANYEXT>(Src);
256}
257
258template <typename SrcTy>
259inline UnaryOp_match<SrcTy, TargetOpcode::G_SEXT> m_GSExt(const SrcTy &Src) {
260 return UnaryOp_match<SrcTy, TargetOpcode::G_SEXT>(Src);
261}
262
263template <typename SrcTy>
264inline UnaryOp_match<SrcTy, TargetOpcode::G_ZEXT> m_GZExt(const SrcTy &Src) {
265 return UnaryOp_match<SrcTy, TargetOpcode::G_ZEXT>(Src);
266}
267
268template <typename SrcTy>
269inline UnaryOp_match<SrcTy, TargetOpcode::G_FPEXT> m_GFPExt(const SrcTy &Src) {
270 return UnaryOp_match<SrcTy, TargetOpcode::G_FPEXT>(Src);
271}
272
273template <typename SrcTy>
274inline UnaryOp_match<SrcTy, TargetOpcode::G_TRUNC> m_GTrunc(const SrcTy &Src) {
275 return UnaryOp_match<SrcTy, TargetOpcode::G_TRUNC>(Src);
276}
277
278template <typename SrcTy>
279inline UnaryOp_match<SrcTy, TargetOpcode::G_BITCAST>
280m_GBitcast(const SrcTy &Src) {
281 return UnaryOp_match<SrcTy, TargetOpcode::G_BITCAST>(Src);
282}
283
284template <typename SrcTy>
285inline UnaryOp_match<SrcTy, TargetOpcode::G_PTRTOINT>
286m_GPtrToInt(const SrcTy &Src) {
287 return UnaryOp_match<SrcTy, TargetOpcode::G_PTRTOINT>(Src);
288}
289
290template <typename SrcTy>
291inline UnaryOp_match<SrcTy, TargetOpcode::G_INTTOPTR>
292m_GIntToPtr(const SrcTy &Src) {
293 return UnaryOp_match<SrcTy, TargetOpcode::G_INTTOPTR>(Src);
294}
295
296template <typename SrcTy>
297inline UnaryOp_match<SrcTy, TargetOpcode::G_FPTRUNC>
298m_GFPTrunc(const SrcTy &Src) {
299 return UnaryOp_match<SrcTy, TargetOpcode::G_FPTRUNC>(Src);
300}
301
302template <typename SrcTy>
303inline UnaryOp_match<SrcTy, TargetOpcode::G_FABS> m_GFabs(const SrcTy &Src) {
304 return UnaryOp_match<SrcTy, TargetOpcode::G_FABS>(Src);
305}
306
307template <typename SrcTy>
308inline UnaryOp_match<SrcTy, TargetOpcode::COPY> m_Copy(SrcTy &&Src) {
309 return UnaryOp_match<SrcTy, TargetOpcode::COPY>(std::forward<SrcTy>(Src));
310}
311
312// Helper for checking if a Reg is of specific type.
313struct CheckType {
314 LLT Ty;
315 CheckType(const LLT &Ty) : Ty(Ty) {}
316
317 bool match(MachineRegisterInfo &MRI, unsigned Reg) {
318 return MRI.getType(Reg) == Ty;
319 }
320};
321
322inline CheckType m_SpecificType(LLT Ty) { return Ty; }
323
324} // namespace GMIPatternMatch
325} // namespace llvm
326
327#endif